diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000000..6db70fd3fc5 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +node_modules +dist +package.json +yarn.lock +package-lock.json +.eslintrc.js \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000000..1c42f15da71 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "trailingComma": "es5", + "singleQuote": true, + "useTabs": true +} diff --git a/package.json b/package.json index bb40eeceb3a..3b01fe5a592 100644 --- a/package.json +++ b/package.json @@ -1,67 +1,70 @@ { - "name": "aws-amplify-monorepo", - "private": true, - "version": "0.1.30", - "description": "", - "scripts": { - "setup-dev": "yarn && yarn bootstrap && yarn link-all && yarn build", - "bootstrap": "lerna bootstrap", - "test": "lerna run test", - "cypress": "lerna run cypress", - "cypress:open": "lerna run cypress:open", - "coverage": "codecov || exit 0", - "docs": "typedoc packages/**/src --name amplify-js --hideGenerator --excludePrivate --ignoreCompilerErrors --mode file --out docs/api --theme docs/amplify-theme/typedoc/", - "build": "lerna run build", - "clean": "lerna run clean", - "format": "lerna run format", - "lint": "lerna run lint", - "link-all": "yarn unlink-all && lerna exec --parallel yarn link", - "unlink-all": "lerna exec --parallel --bail=false yarn unlink", - "publish:master": "lerna publish --canary --yes --dist-tag=unstable --preid=unstable --exact", - "publish:beta": "lerna publish --canary --yes --dist-tag=beta --preid=beta --exact", - "publish:release": "lerna publish --conventional-commits --yes --message 'chore(release): Publish [ci skip]'" - }, - "husky": { - "hooks": {} - }, - "workspaces": [ - "packages/*" - ], - "repository": { - "type": "git", - "url": "https://github.com/aws-amplify/amplify-js.git" - }, - "author": "Amazon Web Services", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/aws-amplify/amplify-js/issues" - }, - "homepage": "https://aws-amplify.github.io/", - "devDependencies": { - "@types/jest": "^20.0.7", - "@types/node": "^8.9.5", - "codecov": "^1.0.1", - "compression-webpack-plugin": "^1.1.3", - "cypress": "^3.2.0", - "husky": "^1.3.1", - "jest": "^22.4.3", - "json-loader": "^0.5.7", - "lerna": "^3.13.1", - "rimraf": "^2.6.2", - "source-map-loader": "^0.2.1", - "ts-jest": "^22.0.0", - "tslint": "^5.7.0", - "tslint-config-airbnb": "^5.8.0", - "typedoc": "^0.11.0", - "typescript": "^2.9.2", - "uglifyjs-webpack-plugin": "^0.4.6", - "webpack": "^3.5.5" - }, - "jest": { - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "/node_modules/ts-jest/preprocessor.js" - }, - "resetMocks": true, - "verbose": true - } + "name": "aws-amplify-monorepo", + "private": true, + "version": "0.1.30", + "description": "", + "scripts": { + "setup-dev": "yarn && yarn bootstrap && yarn link-all && yarn build", + "bootstrap": "lerna bootstrap", + "test": "lerna run test", + "cypress": "lerna run cypress", + "cypress:open": "lerna run cypress:open", + "coverage": "codecov || exit 0", + "docs": "typedoc packages/**/src --name amplify-js --hideGenerator --excludePrivate --ignoreCompilerErrors --mode file --out docs/api --theme docs/amplify-theme/typedoc/", + "build": "lerna run build", + "clean": "lerna run clean", + "format": "lerna run format", + "lint": "lerna run lint", + "link-all": "yarn unlink-all && lerna exec --parallel yarn link", + "unlink-all": "lerna exec --parallel --bail=false yarn unlink", + "publish:master": "lerna publish --canary --yes --dist-tag=unstable --preid=unstable --exact", + "publish:beta": "lerna publish --canary --yes --dist-tag=beta --preid=beta --exact", + "publish:release": "lerna publish --conventional-commits --yes --message 'chore(release): Publish [ci skip]'" + }, + "husky": { + "hooks": { + "pre-commit": "pretty-quick --staged" + } + }, + "workspaces": [ + "packages/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/aws-amplify/amplify-js.git" + }, + "author": "Amazon Web Services", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/aws-amplify/amplify-js/issues" + }, + "homepage": "https://aws-amplify.github.io/", + "devDependencies": { + "@types/jest": "^20.0.7", + "@types/node": "^8.9.5", + "codecov": "^1.0.1", + "compression-webpack-plugin": "^1.1.3", + "cypress": "^3.2.0", + "husky": "^3.0.5", + "jest": "^22.4.3", + "json-loader": "^0.5.7", + "lerna": "^3.13.1", + "pretty-quick": "^1.11.1", + "rimraf": "^2.6.2", + "source-map-loader": "^0.2.1", + "ts-jest": "^22.0.0", + "tslint": "^5.7.0", + "tslint-config-airbnb": "^5.8.0", + "typedoc": "^0.11.0", + "typescript": "^2.9.2", + "uglifyjs-webpack-plugin": "^0.4.6", + "webpack": "^3.5.5" + }, + "jest": { + "transform": { + "^.+\\.(js|jsx|ts|tsx)$": "/node_modules/ts-jest/preprocessor.js" + }, + "resetMocks": true, + "verbose": true + } } diff --git a/packages/amazon-cognito-identity-js/CHANGELOG.md b/packages/amazon-cognito-identity-js/CHANGELOG.md index a1bc9bd13c1..077bfb8f0c3 100644 --- a/packages/amazon-cognito-identity-js/CHANGELOG.md +++ b/packages/amazon-cognito-identity-js/CHANGELOG.md @@ -7,1757 +7,1317 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package amazon-cognito-identity-js - - - - ## [3.0.14](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.13...amazon-cognito-identity-js@3.0.14) (2019-07-18) **Note:** Version bump only for package amazon-cognito-identity-js - - - - -## [3.0.13](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.13-unstable.0...amazon-cognito-identity-js@3.0.13) (2019-06-17) - - +## [3.0.13](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.13-unstable.0...amazon-cognito-identity-js@3.0.13) (2019-06-17) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.13-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.12...amazon-cognito-identity-js@3.0.13-unstable.0) (2019-05-28) +## [3.0.13-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.12...amazon-cognito-identity-js@3.0.13-unstable.0) (2019-05-28) ### Bug Fixes -* **@amazon-cognito-identity-js:** Adds sendMFASelectionAnswer to types ([6c32ef3](https://github.com/aws/aws-amplify/commit/6c32ef3)) - - - +- **@amazon-cognito-identity-js:** Adds sendMFASelectionAnswer to types ([6c32ef3](https://github.com/aws/aws-amplify/commit/6c32ef3)) -## [3.0.12](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.12-unstable.3...amazon-cognito-identity-js@3.0.12) (2019-05-06) - - +## [3.0.12](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.12-unstable.3...amazon-cognito-identity-js@3.0.12) (2019-05-06) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.12-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.12-unstable.2...amazon-cognito-identity-js@3.0.12-unstable.3) (2019-04-26) +## [3.0.12-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.12-unstable.2...amazon-cognito-identity-js@3.0.12-unstable.3) (2019-04-26) ### Features -* **@aws-amplify/amazon-cognito-identity-js:** for signUp, returns CodeDeliveryDetails from response ([7728e11](https://github.com/aws/aws-amplify/commit/7728e11)) - - - +- **@aws-amplify/amazon-cognito-identity-js:** for signUp, returns CodeDeliveryDetails from response ([7728e11](https://github.com/aws/aws-amplify/commit/7728e11)) -## [3.0.12-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.12-unstable.1...amazon-cognito-identity-js@3.0.12-unstable.2) (2019-04-16) +## [3.0.12-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.12-unstable.1...amazon-cognito-identity-js@3.0.12-unstable.2) (2019-04-16) ### Bug Fixes -* **@aws-amplify/auth:** throw error when passing empty object to storage or cookieStorage in configuration ([816a827](https://github.com/aws/aws-amplify/commit/816a827)) - - - +- **@aws-amplify/auth:** throw error when passing empty object to storage or cookieStorage in configuration ([816a827](https://github.com/aws/aws-amplify/commit/816a827)) -## [3.0.12-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.12-unstable.0...amazon-cognito-identity-js@3.0.12-unstable.1) (2019-04-12) - - +## [3.0.12-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.12-unstable.0...amazon-cognito-identity-js@3.0.12-unstable.1) (2019-04-12) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.12-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.11...amazon-cognito-identity-js@3.0.12-unstable.0) (2019-04-12) - - +## [3.0.12-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.11...amazon-cognito-identity-js@3.0.12-unstable.0) (2019-04-12) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.11-unstable.0...amazon-cognito-identity-js@3.0.11) (2019-04-09) - - +## [3.0.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.11-unstable.0...amazon-cognito-identity-js@3.0.11) (2019-04-09) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.11-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.10...amazon-cognito-identity-js@3.0.11-unstable.0) (2019-04-07) - - +## [3.0.11-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.10...amazon-cognito-identity-js@3.0.11-unstable.0) (2019-04-07) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.10-unstable.0...amazon-cognito-identity-js@3.0.10) (2019-03-28) - - +## [3.0.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.10-unstable.0...amazon-cognito-identity-js@3.0.10) (2019-03-28) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.10-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.9...amazon-cognito-identity-js@3.0.10-unstable.0) (2019-03-18) - - +## [3.0.10-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.9...amazon-cognito-identity-js@3.0.10-unstable.0) (2019-03-18) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.9-unstable.0...amazon-cognito-identity-js@3.0.9) (2019-03-06) - - +## [3.0.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.9-unstable.0...amazon-cognito-identity-js@3.0.9) (2019-03-06) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.9-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8...amazon-cognito-identity-js@3.0.9-unstable.0) (2019-03-04) - - +## [3.0.9-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8...amazon-cognito-identity-js@3.0.9-unstable.0) (2019-03-04) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8-unstable.4...amazon-cognito-identity-js@3.0.8) (2019-03-04) - - +## [3.0.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8-unstable.4...amazon-cognito-identity-js@3.0.8) (2019-03-04) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.8-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8-unstable.3...amazon-cognito-identity-js@3.0.8-unstable.4) (2019-03-04) - - +## [3.0.8-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8-unstable.3...amazon-cognito-identity-js@3.0.8-unstable.4) (2019-03-04) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.8-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8-unstable.2...amazon-cognito-identity-js@3.0.8-unstable.3) (2019-03-01) - - +## [3.0.8-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8-unstable.2...amazon-cognito-identity-js@3.0.8-unstable.3) (2019-03-01) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.8-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8-unstable.1...amazon-cognito-identity-js@3.0.8-unstable.2) (2019-02-27) +## [3.0.8-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8-unstable.1...amazon-cognito-identity-js@3.0.8-unstable.2) (2019-02-27) ### Bug Fixes -* **build:** Prevent tree-shaking of crypto-js/lib-typedarrays ([#2718](https://github.com/aws/aws-amplify/issues/2718)) ([3134a64](https://github.com/aws/aws-amplify/commit/3134a64)), closes [#1181](https://github.com/aws/aws-amplify/issues/1181) - - - +- **build:** Prevent tree-shaking of crypto-js/lib-typedarrays ([#2718](https://github.com/aws/aws-amplify/issues/2718)) ([3134a64](https://github.com/aws/aws-amplify/commit/3134a64)), closes [#1181](https://github.com/aws/aws-amplify/issues/1181) -## [3.0.8-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8-unstable.0...amazon-cognito-identity-js@3.0.8-unstable.1) (2019-01-21) - - +## [3.0.8-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.8-unstable.0...amazon-cognito-identity-js@3.0.8-unstable.1) (2019-01-21) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.8-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.7...amazon-cognito-identity-js@3.0.8-unstable.0) (2019-01-18) - - +## [3.0.8-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.7...amazon-cognito-identity-js@3.0.8-unstable.0) (2019-01-18) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.6...amazon-cognito-identity-js@3.0.7) (2019-01-10) +## [3.0.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.6...amazon-cognito-identity-js@3.0.7) (2019-01-10) ### Bug Fixes -* **amazon-cognito-identity-js:** return error instead of undefined ([19c3c4e](https://github.com/aws/aws-amplify/commit/19c3c4e)) -* **amazon-cognito-identity-js:** Update Android Gradle Config ([a08f100](https://github.com/aws/aws-amplify/commit/a08f100)) - - - +- **amazon-cognito-identity-js:** return error instead of undefined ([19c3c4e](https://github.com/aws/aws-amplify/commit/19c3c4e)) +- **amazon-cognito-identity-js:** Update Android Gradle Config ([a08f100](https://github.com/aws/aws-amplify/commit/a08f100)) -## [3.0.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.6-unstable.2...amazon-cognito-identity-js@3.0.6) (2018-12-13) - - +## [3.0.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.6-unstable.2...amazon-cognito-identity-js@3.0.6) (2018-12-13) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.6-unstable.1...amazon-cognito-identity-js@3.0.6-unstable.2) (2018-12-13) +## [3.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.6-unstable.1...amazon-cognito-identity-js@3.0.6-unstable.2) (2018-12-13) ### Features -* **@aws-amplify/auth:** add the option to pass validation data when signing in ([13093e9](https://github.com/aws/aws-amplify/commit/13093e9)) - - - +- **@aws-amplify/auth:** add the option to pass validation data when signing in ([13093e9](https://github.com/aws/aws-amplify/commit/13093e9)) -## [3.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.6-unstable.0...amazon-cognito-identity-js@3.0.6-unstable.1) (2018-12-13) - - +## [3.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.6-unstable.0...amazon-cognito-identity-js@3.0.6-unstable.1) (2018-12-13) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.5...amazon-cognito-identity-js@3.0.6-unstable.0) (2018-12-07) - - +## [3.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.5...amazon-cognito-identity-js@3.0.6-unstable.0) (2018-12-07) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4...amazon-cognito-identity-js@3.0.5) (2018-12-07) - - +## [3.0.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4...amazon-cognito-identity-js@3.0.5) (2018-12-07) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4...amazon-cognito-identity-js@3.0.5-unstable.0) (2018-12-07) +## [3.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4...amazon-cognito-identity-js@3.0.5-unstable.0) (2018-12-07) ### Features -* **amazon-cognito-identity-js:** cache the user data ([f4dd225](https://github.com/aws/aws-amplify/commit/f4dd225)) - - - +- **amazon-cognito-identity-js:** cache the user data ([f4dd225](https://github.com/aws/aws-amplify/commit/f4dd225)) -## [3.0.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.5...amazon-cognito-identity-js@3.0.4) (2018-12-03) - - +## [3.0.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.5...amazon-cognito-identity-js@3.0.4) (2018-12-03) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.4-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.4...amazon-cognito-identity-js@3.0.4-unstable.5) (2018-11-19) +## [3.0.4-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.4...amazon-cognito-identity-js@3.0.4-unstable.5) (2018-11-19) ### Bug Fixes -* **amazon-cognito-identity-js:** Added missing type declarations for setting MFA preferences and token payloads ([080630d](https://github.com/aws/aws-amplify/commit/080630d)) - - - +- **amazon-cognito-identity-js:** Added missing type declarations for setting MFA preferences and token payloads ([080630d](https://github.com/aws/aws-amplify/commit/080630d)) -## [3.0.4-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.3...amazon-cognito-identity-js@3.0.4-unstable.4) (2018-11-19) - - +## [3.0.4-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.3...amazon-cognito-identity-js@3.0.4-unstable.4) (2018-11-19) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.4-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.2...amazon-cognito-identity-js@3.0.4-unstable.3) (2018-11-17) - - +## [3.0.4-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.2...amazon-cognito-identity-js@3.0.4-unstable.3) (2018-11-17) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.4-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.1...amazon-cognito-identity-js@3.0.4-unstable.2) (2018-11-16) - - +## [3.0.4-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.1...amazon-cognito-identity-js@3.0.4-unstable.2) (2018-11-16) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.4-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.0...amazon-cognito-identity-js@3.0.4-unstable.1) (2018-11-16) - - +## [3.0.4-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.4-unstable.0...amazon-cognito-identity-js@3.0.4-unstable.1) (2018-11-16) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.3...amazon-cognito-identity-js@3.0.4-unstable.0) (2018-11-13) - - +## [3.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.3...amazon-cognito-identity-js@3.0.4-unstable.0) (2018-11-13) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.3-unstable.0...amazon-cognito-identity-js@3.0.3) (2018-10-17) - - +## [3.0.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.3-unstable.0...amazon-cognito-identity-js@3.0.3) (2018-10-17) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.2-unstable.0...amazon-cognito-identity-js@3.0.3-unstable.0) (2018-10-05) - - +## [3.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.2-unstable.0...amazon-cognito-identity-js@3.0.3-unstable.0) (2018-10-05) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.2-unstable.0...amazon-cognito-identity-js@3.0.2) (2018-10-04) - - +## [3.0.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@3.0.2-unstable.0...amazon-cognito-identity-js@3.0.2) (2018-10-04) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.31-unstable.2...amazon-cognito-identity-js@3.0.2-unstable.0) (2018-10-03) - - +## [3.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.31-unstable.2...amazon-cognito-identity-js@3.0.2-unstable.0) (2018-10-03) **Note:** Version bump only for package amazon-cognito-identity-js -## [3.0.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.31-unstable.2...amazon-cognito-identity-js@3.0.1) (2018-10-03) - - +## [3.0.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.31-unstable.2...amazon-cognito-identity-js@3.0.1) (2018-10-03) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.31-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.31-unstable.1...amazon-cognito-identity-js@2.0.31-unstable.2) (2018-09-27) +## [2.0.31-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.31-unstable.1...amazon-cognito-identity-js@2.0.31-unstable.2) (2018-09-27) ### Bug Fixes -* **amazon-cognito-identity-js:** replace crypto-browserify with crypto-js ([4d2409a](https://github.com/aws/aws-amplify/commit/4d2409a)) - - - +- **amazon-cognito-identity-js:** replace crypto-browserify with crypto-js ([4d2409a](https://github.com/aws/aws-amplify/commit/4d2409a)) -## [2.0.31-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.31-unstable.0...amazon-cognito-identity-js@2.0.31-unstable.1) (2018-09-27) - - +## [2.0.31-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.31-unstable.0...amazon-cognito-identity-js@2.0.31-unstable.1) (2018-09-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.31-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30...amazon-cognito-identity-js@2.0.31-unstable.0) (2018-09-27) - - +## [2.0.31-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30...amazon-cognito-identity-js@2.0.31-unstable.0) (2018-09-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.30](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.9...amazon-cognito-identity-js@2.0.30) (2018-09-27) - - +## [2.0.30](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.9...amazon-cognito-identity-js@2.0.30) (2018-09-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.30-unstable.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.8...amazon-cognito-identity-js@2.0.30-unstable.9) (2018-09-26) - - +## [2.0.30-unstable.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.8...amazon-cognito-identity-js@2.0.30-unstable.9) (2018-09-26) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.30-unstable.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.7...amazon-cognito-identity-js@2.0.30-unstable.8) (2018-09-26) - - +## [2.0.30-unstable.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.7...amazon-cognito-identity-js@2.0.30-unstable.8) (2018-09-26) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.30-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.6...amazon-cognito-identity-js@2.0.30-unstable.7) (2018-09-26) - - +## [2.0.30-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.6...amazon-cognito-identity-js@2.0.30-unstable.7) (2018-09-26) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.30-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.4...amazon-cognito-identity-js@2.0.30-unstable.6) (2018-09-26) - - +## [2.0.30-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.4...amazon-cognito-identity-js@2.0.30-unstable.6) (2018-09-26) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.30-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.4...amazon-cognito-identity-js@2.0.30-unstable.5) (2018-09-25) - - +## [2.0.30-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.4...amazon-cognito-identity-js@2.0.30-unstable.5) (2018-09-25) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.30-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.3...amazon-cognito-identity-js@2.0.30-unstable.4) (2018-09-25) - - +## [2.0.30-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.3...amazon-cognito-identity-js@2.0.30-unstable.4) (2018-09-25) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.30-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.2...amazon-cognito-identity-js@2.0.30-unstable.3) (2018-09-24) - - +## [2.0.30-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.2...amazon-cognito-identity-js@2.0.30-unstable.3) (2018-09-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.30-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.1...amazon-cognito-identity-js@2.0.30-unstable.2) (2018-09-22) - - +## [2.0.30-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.1...amazon-cognito-identity-js@2.0.30-unstable.2) (2018-09-22) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.30-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.0...amazon-cognito-identity-js@2.0.30-unstable.1) (2018-09-22) - - +## [2.0.30-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.30-unstable.0...amazon-cognito-identity-js@2.0.30-unstable.1) (2018-09-22) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.30-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.29...amazon-cognito-identity-js@2.0.30-unstable.0) (2018-09-22) - - +## [2.0.30-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.29...amazon-cognito-identity-js@2.0.30-unstable.0) (2018-09-22) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.29](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.29-unstable.0...amazon-cognito-identity-js@2.0.29) (2018-09-21) +## [2.0.29](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.29-unstable.0...amazon-cognito-identity-js@2.0.29) (2018-09-21) ### Bug Fixes -* **amazon-cognito-identity-js:** clean clockDrift item when signing out ([f07d800](https://github.com/aws/aws-amplify/commit/f07d800)) - - - +- **amazon-cognito-identity-js:** clean clockDrift item when signing out ([f07d800](https://github.com/aws/aws-amplify/commit/f07d800)) -## [2.0.29-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.28-unstable.3...amazon-cognito-identity-js@2.0.29-unstable.0) (2018-09-21) +## [2.0.29-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.28-unstable.3...amazon-cognito-identity-js@2.0.29-unstable.0) (2018-09-21) ### Bug Fixes -* bumping version for deploying on unstable tag ([#1706](https://github.com/aws/aws-amplify/issues/1706)) ([b5d6468](https://github.com/aws/aws-amplify/commit/b5d6468)) - - - +- bumping version for deploying on unstable tag ([#1706](https://github.com/aws/aws-amplify/issues/1706)) ([b5d6468](https://github.com/aws/aws-amplify/commit/b5d6468)) -## [2.0.28](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.27...amazon-cognito-identity-js@2.0.28) (2018-09-21) - - +## [2.0.28](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.27...amazon-cognito-identity-js@2.0.28) (2018-09-21) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.28-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.28-unstable.2...amazon-cognito-identity-js@2.0.28-unstable.3) (2018-09-20) - - +## [2.0.28-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.28-unstable.2...amazon-cognito-identity-js@2.0.28-unstable.3) (2018-09-20) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.28-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.28-unstable.1...amazon-cognito-identity-js@2.0.28-unstable.2) (2018-09-20) - - +## [2.0.28-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.28-unstable.1...amazon-cognito-identity-js@2.0.28-unstable.2) (2018-09-20) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.28-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.28-unstable.0...amazon-cognito-identity-js@2.0.28-unstable.1) (2018-09-17) - - +## [2.0.28-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.28-unstable.0...amazon-cognito-identity-js@2.0.28-unstable.1) (2018-09-17) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.28-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.27...amazon-cognito-identity-js@2.0.28-unstable.0) (2018-09-17) - - +## [2.0.28-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.27...amazon-cognito-identity-js@2.0.28-unstable.0) (2018-09-17) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.27](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.26...amazon-cognito-identity-js@2.0.27) (2018-09-17) - - +## [2.0.27](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.26...amazon-cognito-identity-js@2.0.27) (2018-09-17) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.26](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.25...amazon-cognito-identity-js@2.0.26) (2018-09-12) - - +## [2.0.26](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.25...amazon-cognito-identity-js@2.0.26) (2018-09-12) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.25](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.25-unstable.0...amazon-cognito-identity-js@2.0.25) (2018-09-09) - - +## [2.0.25](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.25-unstable.0...amazon-cognito-identity-js@2.0.25) (2018-09-09) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.25-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24...amazon-cognito-identity-js@2.0.25-unstable.0) (2018-09-09) - - +## [2.0.25-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24...amazon-cognito-identity-js@2.0.25-unstable.0) (2018-09-09) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.11...amazon-cognito-identity-js@2.0.24) (2018-09-09) - - +## [2.0.24](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.11...amazon-cognito-identity-js@2.0.24) (2018-09-09) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24-unstable.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.10...amazon-cognito-identity-js@2.0.24-unstable.11) (2018-09-08) - - +## [2.0.24-unstable.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.10...amazon-cognito-identity-js@2.0.24-unstable.11) (2018-09-08) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24-unstable.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.9...amazon-cognito-identity-js@2.0.24-unstable.10) (2018-09-07) - - +## [2.0.24-unstable.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.9...amazon-cognito-identity-js@2.0.24-unstable.10) (2018-09-07) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24-unstable.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.8...amazon-cognito-identity-js@2.0.24-unstable.9) (2018-09-07) - - +## [2.0.24-unstable.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.8...amazon-cognito-identity-js@2.0.24-unstable.9) (2018-09-07) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24-unstable.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.7...amazon-cognito-identity-js@2.0.24-unstable.8) (2018-09-07) - - +## [2.0.24-unstable.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.7...amazon-cognito-identity-js@2.0.24-unstable.8) (2018-09-07) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.6...amazon-cognito-identity-js@2.0.24-unstable.7) (2018-09-06) - - +## [2.0.24-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.6...amazon-cognito-identity-js@2.0.24-unstable.7) (2018-09-06) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.5...amazon-cognito-identity-js@2.0.24-unstable.6) (2018-09-06) - - +## [2.0.24-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.5...amazon-cognito-identity-js@2.0.24-unstable.6) (2018-09-06) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.4...amazon-cognito-identity-js@2.0.24-unstable.5) (2018-09-05) - - +## [2.0.24-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.4...amazon-cognito-identity-js@2.0.24-unstable.5) (2018-09-05) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.3...amazon-cognito-identity-js@2.0.24-unstable.4) (2018-09-05) - - +## [2.0.24-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.24-unstable.3...amazon-cognito-identity-js@2.0.24-unstable.4) (2018-09-05) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.23...amazon-cognito-identity-js@2.0.24-unstable.3) (2018-08-31) - - +## [2.0.24-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.23...amazon-cognito-identity-js@2.0.24-unstable.3) (2018-08-31) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.23...amazon-cognito-identity-js@2.0.24-unstable.2) (2018-08-30) - - +## [2.0.24-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.23...amazon-cognito-identity-js@2.0.24-unstable.2) (2018-08-30) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.24-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.23...amazon-cognito-identity-js@2.0.24-unstable.1) (2018-08-30) - - +## [2.0.24-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.23...amazon-cognito-identity-js@2.0.24-unstable.1) (2018-08-30) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.23](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.26...amazon-cognito-identity-js@2.0.23) (2018-08-28) - - +## [2.0.23](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.26...amazon-cognito-identity-js@2.0.23) (2018-08-28) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.26](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.25...amazon-cognito-identity-js@2.0.22-unstable.26) (2018-08-28) - - +## [2.0.22-unstable.26](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.25...amazon-cognito-identity-js@2.0.22-unstable.26) (2018-08-28) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.25](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.24...amazon-cognito-identity-js@2.0.22-unstable.25) (2018-08-27) - - +## [2.0.22-unstable.25](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.24...amazon-cognito-identity-js@2.0.22-unstable.25) (2018-08-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.24](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.23...amazon-cognito-identity-js@2.0.22-unstable.24) (2018-08-27) - - +## [2.0.22-unstable.24](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.23...amazon-cognito-identity-js@2.0.22-unstable.24) (2018-08-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.23](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.21...amazon-cognito-identity-js@2.0.22-unstable.23) (2018-08-27) - - +## [2.0.22-unstable.23](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.21...amazon-cognito-identity-js@2.0.22-unstable.23) (2018-08-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.22](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.21...amazon-cognito-identity-js@2.0.22-unstable.22) (2018-08-25) - - +## [2.0.22-unstable.22](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.21...amazon-cognito-identity-js@2.0.22-unstable.22) (2018-08-25) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.21](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.20...amazon-cognito-identity-js@2.0.22-unstable.21) (2018-08-24) - - +## [2.0.22-unstable.21](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.20...amazon-cognito-identity-js@2.0.22-unstable.21) (2018-08-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.20](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.19...amazon-cognito-identity-js@2.0.22-unstable.20) (2018-08-24) - - +## [2.0.22-unstable.20](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.19...amazon-cognito-identity-js@2.0.22-unstable.20) (2018-08-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.19](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.17...amazon-cognito-identity-js@2.0.22-unstable.19) (2018-08-24) - - +## [2.0.22-unstable.19](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.17...amazon-cognito-identity-js@2.0.22-unstable.19) (2018-08-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.18](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.17...amazon-cognito-identity-js@2.0.22-unstable.18) (2018-08-24) - - +## [2.0.22-unstable.18](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.17...amazon-cognito-identity-js@2.0.22-unstable.18) (2018-08-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.17](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.15...amazon-cognito-identity-js@2.0.22-unstable.17) (2018-08-24) - - +## [2.0.22-unstable.17](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.15...amazon-cognito-identity-js@2.0.22-unstable.17) (2018-08-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.16](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.15...amazon-cognito-identity-js@2.0.22-unstable.16) (2018-08-24) - - +## [2.0.22-unstable.16](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.15...amazon-cognito-identity-js@2.0.22-unstable.16) (2018-08-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.15](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.14...amazon-cognito-identity-js@2.0.22-unstable.15) (2018-08-24) - - +## [2.0.22-unstable.15](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.14...amazon-cognito-identity-js@2.0.22-unstable.15) (2018-08-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.14](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.13...amazon-cognito-identity-js@2.0.22-unstable.14) (2018-08-24) - - +## [2.0.22-unstable.14](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.13...amazon-cognito-identity-js@2.0.22-unstable.14) (2018-08-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.13](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.11...amazon-cognito-identity-js@2.0.22-unstable.13) (2018-08-23) - - +## [2.0.22-unstable.13](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.11...amazon-cognito-identity-js@2.0.22-unstable.13) (2018-08-23) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.12](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.11...amazon-cognito-identity-js@2.0.22-unstable.12) (2018-08-23) - - +## [2.0.22-unstable.12](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.11...amazon-cognito-identity-js@2.0.22-unstable.12) (2018-08-23) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.10...amazon-cognito-identity-js@2.0.22-unstable.11) (2018-08-23) - - +## [2.0.22-unstable.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.10...amazon-cognito-identity-js@2.0.22-unstable.11) (2018-08-23) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.9...amazon-cognito-identity-js@2.0.22-unstable.10) (2018-08-23) - - +## [2.0.22-unstable.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.9...amazon-cognito-identity-js@2.0.22-unstable.10) (2018-08-23) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.8...amazon-cognito-identity-js@2.0.22-unstable.9) (2018-08-23) - - +## [2.0.22-unstable.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.8...amazon-cognito-identity-js@2.0.22-unstable.9) (2018-08-23) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.7...amazon-cognito-identity-js@2.0.22-unstable.8) (2018-08-22) - - +## [2.0.22-unstable.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.7...amazon-cognito-identity-js@2.0.22-unstable.8) (2018-08-22) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.6...amazon-cognito-identity-js@2.0.22-unstable.7) (2018-08-22) - - +## [2.0.22-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.6...amazon-cognito-identity-js@2.0.22-unstable.7) (2018-08-22) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.5...amazon-cognito-identity-js@2.0.22-unstable.6) (2018-08-21) - - +## [2.0.22-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.5...amazon-cognito-identity-js@2.0.22-unstable.6) (2018-08-21) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.4...amazon-cognito-identity-js@2.0.22-unstable.5) (2018-08-21) - - +## [2.0.22-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.4...amazon-cognito-identity-js@2.0.22-unstable.5) (2018-08-21) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.3...amazon-cognito-identity-js@2.0.22-unstable.4) (2018-08-20) - - +## [2.0.22-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.3...amazon-cognito-identity-js@2.0.22-unstable.4) (2018-08-20) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.2...amazon-cognito-identity-js@2.0.22-unstable.3) (2018-08-19) - - +## [2.0.22-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.2...amazon-cognito-identity-js@2.0.22-unstable.3) (2018-08-19) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.1...amazon-cognito-identity-js@2.0.22-unstable.2) (2018-08-18) - - +## [2.0.22-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.1...amazon-cognito-identity-js@2.0.22-unstable.2) (2018-08-18) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.0...amazon-cognito-identity-js@2.0.22-unstable.1) (2018-08-16) - - +## [2.0.22-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.22-unstable.0...amazon-cognito-identity-js@2.0.22-unstable.1) (2018-08-16) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.22-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21...amazon-cognito-identity-js@2.0.22-unstable.0) (2018-08-15) - - +## [2.0.22-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21...amazon-cognito-identity-js@2.0.22-unstable.0) (2018-08-15) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.21](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.5...amazon-cognito-identity-js@2.0.21) (2018-08-14) - - +## [2.0.21](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.5...amazon-cognito-identity-js@2.0.21) (2018-08-14) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.21-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.4...amazon-cognito-identity-js@2.0.21-unstable.5) (2018-08-14) - - +## [2.0.21-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.4...amazon-cognito-identity-js@2.0.21-unstable.5) (2018-08-14) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.21-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.3...amazon-cognito-identity-js@2.0.21-unstable.4) (2018-08-13) - - +## [2.0.21-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.3...amazon-cognito-identity-js@2.0.21-unstable.4) (2018-08-13) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.21-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.2...amazon-cognito-identity-js@2.0.21-unstable.3) (2018-08-13) +## [2.0.21-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.2...amazon-cognito-identity-js@2.0.21-unstable.3) (2018-08-13) ### Bug Fixes -* **amazon-cognito-identity-js:** throw network error if in the offline ([d5808f1](https://github.com/aws/aws-amplify/commit/d5808f1)) - - - +- **amazon-cognito-identity-js:** throw network error if in the offline ([d5808f1](https://github.com/aws/aws-amplify/commit/d5808f1)) -## [2.0.21-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.1...amazon-cognito-identity-js@2.0.21-unstable.2) (2018-08-09) - - +## [2.0.21-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.1...amazon-cognito-identity-js@2.0.21-unstable.2) (2018-08-09) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.21-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.0...amazon-cognito-identity-js@2.0.21-unstable.1) (2018-08-07) - - +## [2.0.21-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.21-unstable.0...amazon-cognito-identity-js@2.0.21-unstable.1) (2018-08-07) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.21-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20...amazon-cognito-identity-js@2.0.21-unstable.0) (2018-08-07) - - +## [2.0.21-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20...amazon-cognito-identity-js@2.0.21-unstable.0) (2018-08-07) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.20](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.7...amazon-cognito-identity-js@2.0.20) (2018-08-06) - - +## [2.0.20](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.7...amazon-cognito-identity-js@2.0.20) (2018-08-06) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.20-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.6...amazon-cognito-identity-js@2.0.20-unstable.7) (2018-08-06) - - +## [2.0.20-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.6...amazon-cognito-identity-js@2.0.20-unstable.7) (2018-08-06) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.20-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.5...amazon-cognito-identity-js@2.0.20-unstable.6) (2018-08-06) - - +## [2.0.20-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.5...amazon-cognito-identity-js@2.0.20-unstable.6) (2018-08-06) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.20-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.3...amazon-cognito-identity-js@2.0.20-unstable.5) (2018-08-06) - - +## [2.0.20-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.3...amazon-cognito-identity-js@2.0.20-unstable.5) (2018-08-06) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.20-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.2...amazon-cognito-identity-js@2.0.20-unstable.3) (2018-07-31) - - +## [2.0.20-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.2...amazon-cognito-identity-js@2.0.20-unstable.3) (2018-07-31) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.20-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.1...amazon-cognito-identity-js@2.0.20-unstable.2) (2018-07-31) - - +## [2.0.20-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.1...amazon-cognito-identity-js@2.0.20-unstable.2) (2018-07-31) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.20-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.0...amazon-cognito-identity-js@2.0.20-unstable.1) (2018-07-30) - - +## [2.0.20-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.20-unstable.0...amazon-cognito-identity-js@2.0.20-unstable.1) (2018-07-30) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.20-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.19...amazon-cognito-identity-js@2.0.20-unstable.0) (2018-07-30) - - +## [2.0.20-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.19...amazon-cognito-identity-js@2.0.20-unstable.0) (2018-07-30) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.19](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.19-unstable.1...amazon-cognito-identity-js@2.0.19) (2018-07-28) - - +## [2.0.19](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.19-unstable.1...amazon-cognito-identity-js@2.0.19) (2018-07-28) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.19-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.18-unstable.0...amazon-cognito-identity-js@2.0.19-unstable.1) (2018-07-28) - - +## [2.0.19-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.18-unstable.0...amazon-cognito-identity-js@2.0.19-unstable.1) (2018-07-28) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.18-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.14...amazon-cognito-identity-js@2.0.18-unstable.0) (2018-07-27) - - +## [2.0.18-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.14...amazon-cognito-identity-js@2.0.18-unstable.0) (2018-07-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.15](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.14...amazon-cognito-identity-js@2.0.17-unstable.15) (2018-07-27) - - +## [2.0.17-unstable.15](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.14...amazon-cognito-identity-js@2.0.17-unstable.15) (2018-07-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.14](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.13...amazon-cognito-identity-js@2.0.17-unstable.14) (2018-07-27) - - +## [2.0.17-unstable.14](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.13...amazon-cognito-identity-js@2.0.17-unstable.14) (2018-07-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.13](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.12...amazon-cognito-identity-js@2.0.17-unstable.13) (2018-07-26) - - +## [2.0.17-unstable.13](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.12...amazon-cognito-identity-js@2.0.17-unstable.13) (2018-07-26) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.12](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.11...amazon-cognito-identity-js@2.0.17-unstable.12) (2018-07-26) - - +## [2.0.17-unstable.12](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.11...amazon-cognito-identity-js@2.0.17-unstable.12) (2018-07-26) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.10...amazon-cognito-identity-js@2.0.17-unstable.11) (2018-07-26) - - +## [2.0.17-unstable.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.10...amazon-cognito-identity-js@2.0.17-unstable.11) (2018-07-26) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.9...amazon-cognito-identity-js@2.0.17-unstable.10) (2018-07-26) - - +## [2.0.17-unstable.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.9...amazon-cognito-identity-js@2.0.17-unstable.10) (2018-07-26) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.8...amazon-cognito-identity-js@2.0.17-unstable.9) (2018-07-25) - - +## [2.0.17-unstable.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.8...amazon-cognito-identity-js@2.0.17-unstable.9) (2018-07-25) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.7...amazon-cognito-identity-js@2.0.17-unstable.8) (2018-07-25) - - +## [2.0.17-unstable.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.7...amazon-cognito-identity-js@2.0.17-unstable.8) (2018-07-25) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.6...amazon-cognito-identity-js@2.0.17-unstable.7) (2018-07-25) - - +## [2.0.17-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.6...amazon-cognito-identity-js@2.0.17-unstable.7) (2018-07-25) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.5...amazon-cognito-identity-js@2.0.17-unstable.6) (2018-07-24) - - +## [2.0.17-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.5...amazon-cognito-identity-js@2.0.17-unstable.6) (2018-07-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.4...amazon-cognito-identity-js@2.0.17-unstable.5) (2018-07-23) +## [2.0.17-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.4...amazon-cognito-identity-js@2.0.17-unstable.5) (2018-07-23) ### Bug Fixes -* **amazon-cognito-identity-js:** add mfa setting type and fix setUserMfaPreference method ([0f8f9aa](https://github.com/aws/aws-amplify/commit/0f8f9aa)) - - - +- **amazon-cognito-identity-js:** add mfa setting type and fix setUserMfaPreference method ([0f8f9aa](https://github.com/aws/aws-amplify/commit/0f8f9aa)) -## [2.0.17-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.3...amazon-cognito-identity-js@2.0.17-unstable.4) (2018-07-23) - - +## [2.0.17-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.3...amazon-cognito-identity-js@2.0.17-unstable.4) (2018-07-23) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.2...amazon-cognito-identity-js@2.0.17-unstable.3) (2018-07-23) - - +## [2.0.17-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.2...amazon-cognito-identity-js@2.0.17-unstable.3) (2018-07-23) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.1...amazon-cognito-identity-js@2.0.17-unstable.2) (2018-07-20) - - +## [2.0.17-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.1...amazon-cognito-identity-js@2.0.17-unstable.2) (2018-07-20) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.0...amazon-cognito-identity-js@2.0.17-unstable.1) (2018-07-20) - - +## [2.0.17-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.17-unstable.0...amazon-cognito-identity-js@2.0.17-unstable.1) (2018-07-20) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.17-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.16...amazon-cognito-identity-js@2.0.17-unstable.0) (2018-07-20) - - +## [2.0.17-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.16...amazon-cognito-identity-js@2.0.17-unstable.0) (2018-07-20) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.16](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.16-unstable.1...amazon-cognito-identity-js@2.0.16) (2018-07-19) - - +## [2.0.16](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.16-unstable.1...amazon-cognito-identity-js@2.0.16) (2018-07-19) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.16-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15...amazon-cognito-identity-js@2.0.16-unstable.1) (2018-07-19) - - +## [2.0.16-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15...amazon-cognito-identity-js@2.0.16-unstable.1) (2018-07-19) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.16-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15...amazon-cognito-identity-js@2.0.16-unstable.0) (2018-07-19) - - +## [2.0.16-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15...amazon-cognito-identity-js@2.0.16-unstable.0) (2018-07-19) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.15](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15-unstable.4...amazon-cognito-identity-js@2.0.15) (2018-07-18) - - +## [2.0.15](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15-unstable.4...amazon-cognito-identity-js@2.0.15) (2018-07-18) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.15-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15-unstable.3...amazon-cognito-identity-js@2.0.15-unstable.4) (2018-07-18) - - +## [2.0.15-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15-unstable.3...amazon-cognito-identity-js@2.0.15-unstable.4) (2018-07-18) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.15-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15-unstable.2...amazon-cognito-identity-js@2.0.15-unstable.3) (2018-07-18) - - +## [2.0.15-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15-unstable.2...amazon-cognito-identity-js@2.0.15-unstable.3) (2018-07-18) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.15-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15-unstable.1...amazon-cognito-identity-js@2.0.15-unstable.2) (2018-07-18) - - +## [2.0.15-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15-unstable.1...amazon-cognito-identity-js@2.0.15-unstable.2) (2018-07-18) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.15-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15...amazon-cognito-identity-js@2.0.15-unstable.1) (2018-07-18) - - +## [2.0.15-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15...amazon-cognito-identity-js@2.0.15-unstable.1) (2018-07-18) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.15-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15...amazon-cognito-identity-js@2.0.15-unstable.0) (2018-07-18) - - +## [2.0.15-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.15...amazon-cognito-identity-js@2.0.15-unstable.0) (2018-07-18) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.14-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.14-unstable.0...amazon-cognito-identity-js@2.0.14-unstable.1) (2018-07-03) +## [2.0.14-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.14-unstable.0...amazon-cognito-identity-js@2.0.14-unstable.1) (2018-07-03) ### Bug Fixes -* **amazon-cognito-identity-js:** attach raw message for unknown errors ([203d50b](https://github.com/aws/aws-amplify/commit/203d50b)) -* **amazon-cognito-identity-js:** attach raw message for unknown errors ([69be072](https://github.com/aws/aws-amplify/commit/69be072)) - - - +- **amazon-cognito-identity-js:** attach raw message for unknown errors ([203d50b](https://github.com/aws/aws-amplify/commit/203d50b)) +- **amazon-cognito-identity-js:** attach raw message for unknown errors ([69be072](https://github.com/aws/aws-amplify/commit/69be072)) -## [2.0.14-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13...amazon-cognito-identity-js@2.0.14-unstable.0) (2018-07-02) - - +## [2.0.14-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13...amazon-cognito-identity-js@2.0.14-unstable.0) (2018-07-02) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.13](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.5...amazon-cognito-identity-js@2.0.13) (2018-06-29) - - +## [2.0.13](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.5...amazon-cognito-identity-js@2.0.13) (2018-06-29) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.13-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.4...amazon-cognito-identity-js@2.0.13-unstable.5) (2018-06-29) - - +## [2.0.13-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.4...amazon-cognito-identity-js@2.0.13-unstable.5) (2018-06-29) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.13-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.3...amazon-cognito-identity-js@2.0.13-unstable.4) (2018-06-29) - - +## [2.0.13-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.3...amazon-cognito-identity-js@2.0.13-unstable.4) (2018-06-29) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.13-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.2...amazon-cognito-identity-js@2.0.13-unstable.3) (2018-06-28) - - +## [2.0.13-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.2...amazon-cognito-identity-js@2.0.13-unstable.3) (2018-06-28) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.13-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.1...amazon-cognito-identity-js@2.0.13-unstable.2) (2018-06-27) - - +## [2.0.13-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.1...amazon-cognito-identity-js@2.0.13-unstable.2) (2018-06-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.13-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.0...amazon-cognito-identity-js@2.0.13-unstable.1) (2018-06-27) - - +## [2.0.13-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.13-unstable.0...amazon-cognito-identity-js@2.0.13-unstable.1) (2018-06-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.13-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.12-unstable.2...amazon-cognito-identity-js@2.0.13-unstable.0) (2018-06-27) - - +## [2.0.13-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.12-unstable.2...amazon-cognito-identity-js@2.0.13-unstable.0) (2018-06-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.12](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.12-unstable.2...amazon-cognito-identity-js@2.0.12) (2018-06-27) - - +## [2.0.12](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.12-unstable.2...amazon-cognito-identity-js@2.0.12) (2018-06-27) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.12-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.12-unstable.1...amazon-cognito-identity-js@2.0.12-unstable.2) (2018-06-26) - - +## [2.0.12-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.12-unstable.1...amazon-cognito-identity-js@2.0.12-unstable.2) (2018-06-26) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.12-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.12-unstable.0...amazon-cognito-identity-js@2.0.12-unstable.1) (2018-06-22) - - +## [2.0.12-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.12-unstable.0...amazon-cognito-identity-js@2.0.12-unstable.1) (2018-06-22) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.12-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.11...amazon-cognito-identity-js@2.0.12-unstable.0) (2018-06-22) - - +## [2.0.12-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.11...amazon-cognito-identity-js@2.0.12-unstable.0) (2018-06-22) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.10-unstable.3...amazon-cognito-identity-js@2.0.11) (2018-06-21) - - +## [2.0.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.10-unstable.3...amazon-cognito-identity-js@2.0.11) (2018-06-21) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.49...amazon-cognito-identity-js@2.0.10) (2018-06-20) - -## [2.0.10-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.10-unstable.2...amazon-cognito-identity-js@2.0.10-unstable.3) (2018-06-21) +## [2.0.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.49...amazon-cognito-identity-js@2.0.10) (2018-06-20) + +## [2.0.10-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.10-unstable.2...amazon-cognito-identity-js@2.0.10-unstable.3) (2018-06-21) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.10-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.10-unstable.1...amazon-cognito-identity-js@2.0.10-unstable.2) (2018-06-21) - - +## [2.0.10-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.10-unstable.1...amazon-cognito-identity-js@2.0.10-unstable.2) (2018-06-21) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.10-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.10-unstable.0...amazon-cognito-identity-js@2.0.10-unstable.1) (2018-06-20) - - +## [2.0.10-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.10-unstable.0...amazon-cognito-identity-js@2.0.10-unstable.1) (2018-06-20) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.10-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.49...amazon-cognito-identity-js@2.0.10-unstable.0) (2018-06-20) +## [2.0.10-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.49...amazon-cognito-identity-js@2.0.10-unstable.0) (2018-06-20) ### Bug Fixes -* **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) - - - +- **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) -## [2.0.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.35...amazon-cognito-identity-js@2.0.9) (2018-06-04) +## [2.0.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.35...amazon-cognito-identity-js@2.0.9) (2018-06-04) ### Bug Fixes -* **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) - - - +- **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) -## [2.0.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7...amazon-cognito-identity-js@2.0.8) (2018-06-02) - -## [2.0.7-unstable.49](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.48...amazon-cognito-identity-js@2.0.7-unstable.49) (2018-06-19) +## [2.0.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7...amazon-cognito-identity-js@2.0.8) (2018-06-02) + +## [2.0.7-unstable.49](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.48...amazon-cognito-identity-js@2.0.7-unstable.49) (2018-06-19) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.48](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.47...amazon-cognito-identity-js@2.0.7-unstable.48) (2018-06-18) - - +## [2.0.7-unstable.48](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.47...amazon-cognito-identity-js@2.0.7-unstable.48) (2018-06-18) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.47](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.46...amazon-cognito-identity-js@2.0.7-unstable.47) (2018-06-18) - - +## [2.0.7-unstable.47](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.46...amazon-cognito-identity-js@2.0.7-unstable.47) (2018-06-18) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.46](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.45...amazon-cognito-identity-js@2.0.7-unstable.46) (2018-06-16) - - +## [2.0.7-unstable.46](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.45...amazon-cognito-identity-js@2.0.7-unstable.46) (2018-06-16) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.45](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.44...amazon-cognito-identity-js@2.0.7-unstable.45) (2018-06-13) - - +## [2.0.7-unstable.45](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.44...amazon-cognito-identity-js@2.0.7-unstable.45) (2018-06-13) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.44](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.43...amazon-cognito-identity-js@2.0.7-unstable.44) (2018-06-13) - - +## [2.0.7-unstable.44](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.43...amazon-cognito-identity-js@2.0.7-unstable.44) (2018-06-13) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.43](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.42...amazon-cognito-identity-js@2.0.7-unstable.43) (2018-06-12) - - +## [2.0.7-unstable.43](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.42...amazon-cognito-identity-js@2.0.7-unstable.43) (2018-06-12) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.42](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.41...amazon-cognito-identity-js@2.0.7-unstable.42) (2018-06-11) - - +## [2.0.7-unstable.42](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.41...amazon-cognito-identity-js@2.0.7-unstable.42) (2018-06-11) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.41](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.40...amazon-cognito-identity-js@2.0.7-unstable.41) (2018-06-08) - - +## [2.0.7-unstable.41](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.40...amazon-cognito-identity-js@2.0.7-unstable.41) (2018-06-08) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.40](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.39...amazon-cognito-identity-js@2.0.7-unstable.40) (2018-06-08) - - +## [2.0.7-unstable.40](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.39...amazon-cognito-identity-js@2.0.7-unstable.40) (2018-06-08) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.39](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.38...amazon-cognito-identity-js@2.0.7-unstable.39) (2018-06-07) - - +## [2.0.7-unstable.39](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.38...amazon-cognito-identity-js@2.0.7-unstable.39) (2018-06-07) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.38](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.37...amazon-cognito-identity-js@2.0.7-unstable.38) (2018-06-06) - - +## [2.0.7-unstable.38](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.37...amazon-cognito-identity-js@2.0.7-unstable.38) (2018-06-06) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.37](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.36...amazon-cognito-identity-js@2.0.7-unstable.37) (2018-06-05) - - +## [2.0.7-unstable.37](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.36...amazon-cognito-identity-js@2.0.7-unstable.37) (2018-06-05) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.36](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.35...amazon-cognito-identity-js@2.0.7-unstable.36) (2018-06-04) - - +## [2.0.7-unstable.36](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.35...amazon-cognito-identity-js@2.0.7-unstable.36) (2018-06-04) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.35](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.34...amazon-cognito-identity-js@2.0.7-unstable.35) (2018-06-04) - - +## [2.0.7-unstable.35](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.34...amazon-cognito-identity-js@2.0.7-unstable.35) (2018-06-04) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.32...amazon-cognito-identity-js@2.0.7) (2018-06-01) - -## [2.0.7-unstable.34](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.33...amazon-cognito-identity-js@2.0.7-unstable.34) (2018-06-04) +## [2.0.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.32...amazon-cognito-identity-js@2.0.7) (2018-06-01) + +## [2.0.7-unstable.34](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.33...amazon-cognito-identity-js@2.0.7-unstable.34) (2018-06-04) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.33](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.32...amazon-cognito-identity-js@2.0.7-unstable.33) (2018-06-02) - - +## [2.0.7-unstable.33](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.32...amazon-cognito-identity-js@2.0.7-unstable.33) (2018-06-02) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.32](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.31...amazon-cognito-identity-js@2.0.7-unstable.32) (2018-06-01) - - +## [2.0.7-unstable.32](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.31...amazon-cognito-identity-js@2.0.7-unstable.32) (2018-06-01) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.31](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.30...amazon-cognito-identity-js@2.0.7-unstable.31) (2018-06-01) - - +## [2.0.7-unstable.31](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.30...amazon-cognito-identity-js@2.0.7-unstable.31) (2018-06-01) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.30](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.29...amazon-cognito-identity-js@2.0.7-unstable.30) (2018-06-01) - - +## [2.0.7-unstable.30](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.29...amazon-cognito-identity-js@2.0.7-unstable.30) (2018-06-01) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.29](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.28...amazon-cognito-identity-js@2.0.7-unstable.29) (2018-05-31) - - +## [2.0.7-unstable.29](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.28...amazon-cognito-identity-js@2.0.7-unstable.29) (2018-05-31) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.28](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.23...amazon-cognito-identity-js@2.0.7-unstable.28) (2018-05-31) - - +## [2.0.7-unstable.28](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.23...amazon-cognito-identity-js@2.0.7-unstable.28) (2018-05-31) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.23](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.22...amazon-cognito-identity-js@2.0.7-unstable.23) (2018-05-31) - - +## [2.0.7-unstable.23](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.22...amazon-cognito-identity-js@2.0.7-unstable.23) (2018-05-31) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.22](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.21...amazon-cognito-identity-js@2.0.7-unstable.22) (2018-05-31) - - +## [2.0.7-unstable.22](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.21...amazon-cognito-identity-js@2.0.7-unstable.22) (2018-05-31) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.21](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.20...amazon-cognito-identity-js@2.0.7-unstable.21) (2018-05-30) - - +## [2.0.7-unstable.21](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.20...amazon-cognito-identity-js@2.0.7-unstable.21) (2018-05-30) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.20](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.19...amazon-cognito-identity-js@2.0.7-unstable.20) (2018-05-29) - - +## [2.0.7-unstable.20](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.19...amazon-cognito-identity-js@2.0.7-unstable.20) (2018-05-29) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.19](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.18...amazon-cognito-identity-js@2.0.7-unstable.19) (2018-05-29) - - +## [2.0.7-unstable.19](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.18...amazon-cognito-identity-js@2.0.7-unstable.19) (2018-05-29) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.18](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.17...amazon-cognito-identity-js@2.0.7-unstable.18) (2018-05-29) - - +## [2.0.7-unstable.18](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.17...amazon-cognito-identity-js@2.0.7-unstable.18) (2018-05-29) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.17](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.16...amazon-cognito-identity-js@2.0.7-unstable.17) (2018-05-24) - - +## [2.0.7-unstable.17](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.16...amazon-cognito-identity-js@2.0.7-unstable.17) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.16](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.15...amazon-cognito-identity-js@2.0.7-unstable.16) (2018-05-24) - - +## [2.0.7-unstable.16](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.15...amazon-cognito-identity-js@2.0.7-unstable.16) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.15](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.14...amazon-cognito-identity-js@2.0.7-unstable.15) (2018-05-24) - - +## [2.0.7-unstable.15](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.14...amazon-cognito-identity-js@2.0.7-unstable.15) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.14](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.13...amazon-cognito-identity-js@2.0.7-unstable.14) (2018-05-24) - - +## [2.0.7-unstable.14](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.13...amazon-cognito-identity-js@2.0.7-unstable.14) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.13](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.12...amazon-cognito-identity-js@2.0.7-unstable.13) (2018-05-24) - - +## [2.0.7-unstable.13](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.12...amazon-cognito-identity-js@2.0.7-unstable.13) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.12](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.11...amazon-cognito-identity-js@2.0.7-unstable.12) (2018-05-24) - - +## [2.0.7-unstable.12](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.11...amazon-cognito-identity-js@2.0.7-unstable.12) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.10...amazon-cognito-identity-js@2.0.7-unstable.11) (2018-05-24) - - +## [2.0.7-unstable.11](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.10...amazon-cognito-identity-js@2.0.7-unstable.11) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.6...amazon-cognito-identity-js@2.0.7-unstable.10) (2018-05-24) - - +## [2.0.7-unstable.10](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.6...amazon-cognito-identity-js@2.0.7-unstable.10) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.8...amazon-cognito-identity-js@2.0.7-unstable.9) (2018-05-24) - - +## [2.0.7-unstable.9](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.8...amazon-cognito-identity-js@2.0.7-unstable.9) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.7...amazon-cognito-identity-js@2.0.7-unstable.8) (2018-05-24) - - +## [2.0.7-unstable.8](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.7...amazon-cognito-identity-js@2.0.7-unstable.8) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.6...amazon-cognito-identity-js@2.0.7-unstable.7) (2018-05-24) - - +## [2.0.7-unstable.7](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.6...amazon-cognito-identity-js@2.0.7-unstable.7) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.5...amazon-cognito-identity-js@2.0.7-unstable.6) (2018-05-24) - - +## [2.0.7-unstable.6](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.5...amazon-cognito-identity-js@2.0.7-unstable.6) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.4...amazon-cognito-identity-js@2.0.7-unstable.5) (2018-05-24) - - +## [2.0.7-unstable.5](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.4...amazon-cognito-identity-js@2.0.7-unstable.5) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.3...amazon-cognito-identity-js@2.0.7-unstable.4) (2018-05-24) - - +## [2.0.7-unstable.4](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.3...amazon-cognito-identity-js@2.0.7-unstable.4) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.2...amazon-cognito-identity-js@2.0.7-unstable.3) (2018-05-24) - - +## [2.0.7-unstable.3](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.2...amazon-cognito-identity-js@2.0.7-unstable.3) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.1...amazon-cognito-identity-js@2.0.7-unstable.2) (2018-05-24) - - +## [2.0.7-unstable.2](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.1...amazon-cognito-identity-js@2.0.7-unstable.2) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.0...amazon-cognito-identity-js@2.0.7-unstable.1) (2018-05-24) - - +## [2.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.7-unstable.0...amazon-cognito-identity-js@2.0.7-unstable.1) (2018-05-24) **Note:** Version bump only for package amazon-cognito-identity-js -## [2.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.6...amazon-cognito-identity-js@2.0.7-unstable.0) (2018-05-23) - - +## [2.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/amazon-cognito-identity-js@2.0.6...amazon-cognito-identity-js@2.0.7-unstable.0) (2018-05-23) **Note:** Version bump only for package amazon-cognito-identity-js diff --git a/packages/amazon-cognito-identity-js/README.md b/packages/amazon-cognito-identity-js/README.md index 751e8800b1d..fcfb35ba6a3 100644 --- a/packages/amazon-cognito-identity-js/README.md +++ b/packages/amazon-cognito-identity-js/README.md @@ -4,28 +4,29 @@ You can now use Amazon Cognito to easily add user sign-up and sign-in to your mo We welcome developer feedback on this project. You can reach us by creating an issue on the GitHub repository or posting to the Amazon Cognito Identity forums and the below blog post: -* https://github.com/aws-amplify/amplify-js -* https://forums.aws.amazon.com/forum.jspa?forumID=173 -* https://aws.amazon.com/blogs/mobile/accessing-your-user-pools-using-the-amazon-cognito-identity-sdk-for-javascript/ + +- https://github.com/aws-amplify/amplify-js +- https://forums.aws.amazon.com/forum.jspa?forumID=173 +- https://aws.amazon.com/blogs/mobile/accessing-your-user-pools-using-the-amazon-cognito-identity-sdk-for-javascript/ For an overview of the Cognito authentication flow, refer to the following blog post: -* https://aws.amazon.com/blogs/mobile/customizing-your-user-pool-authentication-flow/ -Introduction -============ +- https://aws.amazon.com/blogs/mobile/customizing-your-user-pool-authentication-flow/ + +# Introduction + The Amazon Cognito Identity SDK for JavaScript allows JavaScript enabled applications to sign-up users, authenticate users, view, delete, and update user attributes within the Amazon Cognito Identity service. Other functionality includes password changes for authenticated users and initiating and completing forgot password flows for unauthenticated users. Your users will benefit from a number of security features including SMS-based Multi-Factor Authentication (MFA) and account verification via phone or email. The password features use the Secure Remote Password (SRP) protocol to avoid sending cleartext passwords over the wire. -Setup -===== +# Setup There are two ways to install the Amazon Cognito Identity SDK for JavaScript and its dependencies, depending on your project setup and experience with modern JavaScript build tools: -* Download the bundle file from npm and include it in your HTML, or +- Download the bundle file from npm and include it in your HTML, or -* Install the dependencies with npm and use a bundler like webpack. +- Install the dependencies with npm and use a bundler like webpack. **Note:** This library uses the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). For [older browsers](https://caniuse.com/#feat=fetch) or in Node.js, you may need to include a polyfill. For example. @@ -48,9 +49,9 @@ Optionally, to use other AWS services, include a build of the [AWS SDK for JavaS Include all of the files in your HTML page before calling any Amazon Cognito Identity SDK APIs: ```html - - - + + + ``` ## Using NPM and Webpack @@ -68,17 +69,17 @@ if you are using a transpiler such as [Babel](https://babeljs.io/).) If your pro may wish to use [Webpack's module shimming features](http://webpack.github.io/docs/shimming-modules.html) to ease migration. -* Install [Node.js](https://nodejs.org) on your development machine (this will not be needed on your server.) +- Install [Node.js](https://nodejs.org) on your development machine (this will not be needed on your server.) -* In your project add a `package.json`, either use `npm init` or the minimal: +- In your project add a `package.json`, either use `npm init` or the minimal: ```json { - "private": true + "private": true } ``` -* Install the Amazon Cognito Identity SDK for JavaScript and the Webpack tool into your project with `npm` (the Node +- Install the Amazon Cognito Identity SDK for JavaScript and the Webpack tool into your project with `npm` (the Node Package Manager, which is installed with Node.js): ``` @@ -91,66 +92,66 @@ migration. parameters will update the `package.json` file with instructions on what should be installed, so you can simply call `npm install` without any parameters to recreate this folder later. -* Create the configuration file for `webpack`, named `webpack.config.js`: +- Create the configuration file for `webpack`, named `webpack.config.js`: ```js module.exports = { - // Example setup for your project: - // The entry module that requires or imports the rest of your project. - // Must start with `./`! - entry: './src/entry.js', - // Place output files in `./dist/my-app.js` - output: { - path: __dirname + '/dist', - filename: 'my-app.js' - }, - module: { - rules: [ - { - test: /\.json$/, - loader: 'json-loader' - } - ] - } + // Example setup for your project: + // The entry module that requires or imports the rest of your project. + // Must start with `./`! + entry: './src/entry.js', + // Place output files in `./dist/my-app.js` + output: { + path: __dirname + '/dist', + filename: 'my-app.js', + }, + module: { + rules: [ + { + test: /\.json$/, + loader: 'json-loader', + }, + ], + }, }; ``` -* Create the following directory where `webpack.config.js` resides, and create the entry file: +- Create the following directory where `webpack.config.js` resides, and create the entry file: ``` > mkdir -p src > touch src/entry.js ``` -* Add the following into your `package.json` +- Add the following into your `package.json` ```json { - "scripts": { - "build": "webpack" - } + "scripts": { + "build": "webpack" + } } ``` -* Build your application bundle with `npm run build` +- Build your application bundle with `npm run build` ## Install for React Native See [Using NPM and Webpack](https://github.com/aws/amazon-cognito-identity-js#using-npm-and-webpack) for more information on NPM. -* Install and add to your dependencies the Amazon Cognito Identity SDK for JavaScript: +- Install and add to your dependencies the Amazon Cognito Identity SDK for JavaScript: ``` npm install --save amazon-cognito-identity-js ``` -* Install react-native-cli if you have not already: +- Install react-native-cli if you have not already: ``` npm install -g react-native-cli ``` -* Link the native modules to your project: +- Link the native modules to your project: ``` react-native link amazon-cognito-identity-js @@ -161,9 +162,9 @@ react-native link amazon-cognito-identity-js The Amazon Cognito Identity SDK for JavaScript requires two configuration values from your AWS Account in order to access your Cognito User Pool: -* The User Pool Id, e.g. `us-east-1_aB12cDe34` -* A User Pool App Client Id, e.g. `7ghr5379orhbo88d52vphda6s9` - * When creating the App, the generate client secret box must be **unchecked** because the +- The User Pool Id, e.g. `us-east-1_aB12cDe34` +- A User Pool App Client Id, e.g. `7ghr5379orhbo88d52vphda6s9` + - When creating the App, the generate client secret box must be **unchecked** because the JavaScript SDK doesn't support apps that have a client secret. The [AWS Console for Cognito User Pools](https://console.aws.amazon.com/cognito/users/) can be used to get or create these values. @@ -188,146 +189,155 @@ If you are having issues when using Aurelia, please see the following [Stack Ove ## Usage The usage examples below use the unqualified names for types in the Amazon Cognito Identity SDK for JavaScript. Remember to import or qualify access to any of these types: - -```javascript - // When using loose Javascript files: - var CognitoUserPool = AmazonCognitoIdentity.CognitoUserPool; - // Modules, e.g. Webpack: - var AmazonCognitoIdentity = require('amazon-cognito-identity-js'); - var CognitoUserPool = AmazonCognitoIdentity.CognitoUserPool; +```javascript +// When using loose Javascript files: +var CognitoUserPool = AmazonCognitoIdentity.CognitoUserPool; - // ES Modules, e.g. transpiling with Babel - import { CognitoUserPool, CognitoUserAttribute, CognitoUser } from 'amazon-cognito-identity-js'; +// Modules, e.g. Webpack: +var AmazonCognitoIdentity = require('amazon-cognito-identity-js'); +var CognitoUserPool = AmazonCognitoIdentity.CognitoUserPool; + +// ES Modules, e.g. transpiling with Babel +import { + CognitoUserPool, + CognitoUserAttribute, + CognitoUser, +} from 'amazon-cognito-identity-js'; ``` **Use case 1.** Registering a user with the application. One needs to create a CognitoUserPool object by providing a UserPoolId and a ClientId and signing up by using a username, password, attribute list, and validation data. ```javascript - - var poolData = { - UserPoolId : '...', // Your user pool id here - ClientId : '...' // Your client id here - }; - var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); - - var attributeList = []; - - var dataEmail = { - Name : 'email', - Value : 'email@mydomain.com' - }; - - var dataPhoneNumber = { - Name : 'phone_number', - Value : '+15555555555' - }; - var attributeEmail = new AmazonCognitoIdentity.CognitoUserAttribute(dataEmail); - var attributePhoneNumber = new AmazonCognitoIdentity.CognitoUserAttribute(dataPhoneNumber); - - attributeList.push(attributeEmail); - attributeList.push(attributePhoneNumber); - - userPool.signUp('username', 'password', attributeList, null, function(err, result){ - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - var cognitoUser = result.user; - console.log('user name is ' + cognitoUser.getUsername()); - }); +var poolData = { + UserPoolId: '...', // Your user pool id here + ClientId: '...', // Your client id here +}; +var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); + +var attributeList = []; + +var dataEmail = { + Name: 'email', + Value: 'email@mydomain.com', +}; + +var dataPhoneNumber = { + Name: 'phone_number', + Value: '+15555555555', +}; +var attributeEmail = new AmazonCognitoIdentity.CognitoUserAttribute(dataEmail); +var attributePhoneNumber = new AmazonCognitoIdentity.CognitoUserAttribute( + dataPhoneNumber +); + +attributeList.push(attributeEmail); +attributeList.push(attributePhoneNumber); + +userPool.signUp('username', 'password', attributeList, null, function( + err, + result +) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + var cognitoUser = result.user; + console.log('user name is ' + cognitoUser.getUsername()); +}); ``` **Use case 2.** Confirming a registered, unauthenticated user using a confirmation code received via SMS. ```javascript - var poolData = { - UserPoolId : '...', // Your user pool id here - ClientId : '...' // Your client id here - }; - - var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); - var userData = { - Username : 'username', - Pool : userPool - }; - - var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData); - cognitoUser.confirmRegistration('123456', true, function(err, result) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('call result: ' + result); - }); +var poolData = { + UserPoolId: '...', // Your user pool id here + ClientId: '...', // Your client id here +}; + +var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); +var userData = { + Username: 'username', + Pool: userPool, +}; + +var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData); +cognitoUser.confirmRegistration('123456', true, function(err, result) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('call result: ' + result); +}); ``` **Use case 3.** Resending a confirmation code via SMS for confirming registration for a unauthenticated user. ```javascript - cognitoUser.resendConfirmationCode(function(err, result) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('call result: ' + result); - }); +cognitoUser.resendConfirmationCode(function(err, result) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('call result: ' + result); +}); ``` **Use case 4.** Authenticating a user and establishing a user session with the Amazon Cognito Identity service. - ```javascript - - import * as AWS from 'aws-sdk/global'; - - var authenticationData = { - Username : 'username', - Password : 'password', - }; - var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData); - var poolData = { - UserPoolId : '...', // Your user pool id here - ClientId : '...' // Your client id here - }; - var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); - var userData = { - Username : 'username', - Pool : userPool - }; - var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData); - cognitoUser.authenticateUser(authenticationDetails, { - onSuccess: function (result) { - var accessToken = result.getAccessToken().getJwtToken(); - - //POTENTIAL: Region needs to be set if not already set previously elsewhere. - AWS.config.region = ''; - - AWS.config.credentials = new AWS.CognitoIdentityCredentials({ - IdentityPoolId : '...', // your identity pool id here - Logins : { - // Change the key below according to the specific region your user pool is in. - 'cognito-idp..amazonaws.com/' : result.getIdToken().getJwtToken() - } - }); - - //refreshes credentials using AWS.CognitoIdentity.getCredentialsForIdentity() - AWS.config.credentials.refresh((error) => { - if (error) { - console.error(error); - } else { - // Instantiate aws sdk service objects now that the credentials have been updated. - // example: var s3 = new AWS.S3(); - console.log('Successfully logged!'); - } - }); - }, - - onFailure: function(err) { - alert(err.message || JSON.stringify(err)); - }, - - }); +import * as AWS from 'aws-sdk/global'; + +var authenticationData = { + Username: 'username', + Password: 'password', +}; +var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails( + authenticationData +); +var poolData = { + UserPoolId: '...', // Your user pool id here + ClientId: '...', // Your client id here +}; +var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); +var userData = { + Username: 'username', + Pool: userPool, +}; +var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData); +cognitoUser.authenticateUser(authenticationDetails, { + onSuccess: function(result) { + var accessToken = result.getAccessToken().getJwtToken(); + + //POTENTIAL: Region needs to be set if not already set previously elsewhere. + AWS.config.region = ''; + + AWS.config.credentials = new AWS.CognitoIdentityCredentials({ + IdentityPoolId: '...', // your identity pool id here + Logins: { + // Change the key below according to the specific region your user pool is in. + 'cognito-idp..amazonaws.com/': result + .getIdToken() + .getJwtToken(), + }, + }); + + //refreshes credentials using AWS.CognitoIdentity.getCredentialsForIdentity() + AWS.config.credentials.refresh(error => { + if (error) { + console.error(error); + } else { + // Instantiate aws sdk service objects now that the credentials have been updated. + // example: var s3 = new AWS.S3(); + console.log('Successfully logged!'); + } + }); + }, + + onFailure: function(err) { + alert(err.message || JSON.stringify(err)); + }, +}); ``` Note that if device tracking is enabled for the user pool with a setting that user opt-in is required, you need to implement an onSuccess(result, userConfirmationNecessary) callback, collect user input and call either setDeviceStatusRemembered to remember the device or setDeviceStatusNotRemembered to not remember the device. @@ -337,15 +347,17 @@ Note also that if CognitoUser.authenticateUser throws ReferenceError: navigator **Use case 5.** Retrieve user attributes for an authenticated user. ```javascript - cognitoUser.getUserAttributes(function(err, result) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - for (i = 0; i < result.length; i++) { - console.log('attribute ' + result[i].getName() + ' has value ' + result[i].getValue()); - } - }); +cognitoUser.getUserAttributes(function(err, result) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + for (i = 0; i < result.length; i++) { + console.log( + 'attribute ' + result[i].getName() + ' has value ' + result[i].getValue() + ); + } +}); ``` **Use case 6.** Verify user attribute for an authenticated user. @@ -353,53 +365,53 @@ Note also that if CognitoUser.authenticateUser throws ReferenceError: navigator Note that the inputVerificationCode method needs to be defined but does not need to actually do anything. If you would like the user to input the verification code on another page, you can set inputVerificationCode to null. If inputVerificationCode is null, onSuccess will be called immediately (assuming there is no error). ```javascript - cognitoUser.getAttributeVerificationCode('email', { - onSuccess: function (result) { - console.log('call result: ' + result); - }, - onFailure: function(err) { - alert(err.message || JSON.stringify(err)); - }, - inputVerificationCode: function() { - var verificationCode = prompt('Please input verification code: ' ,''); - cognitoUser.verifyAttribute('email', verificationCode, this); - } - }); +cognitoUser.getAttributeVerificationCode('email', { + onSuccess: function(result) { + console.log('call result: ' + result); + }, + onFailure: function(err) { + alert(err.message || JSON.stringify(err)); + }, + inputVerificationCode: function() { + var verificationCode = prompt('Please input verification code: ', ''); + cognitoUser.verifyAttribute('email', verificationCode, this); + }, +}); ``` **Use case 7.** Delete user attribute for an authenticated user. ```javascript - var attributeList = []; - attributeList.push('nickname'); - - cognitoUser.deleteAttributes(attributeList, function(err, result) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('call result: ' + result); - }); +var attributeList = []; +attributeList.push('nickname'); + +cognitoUser.deleteAttributes(attributeList, function(err, result) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('call result: ' + result); +}); ``` **Use case 8.** Update user attributes for an authenticated user. ```javascript - var attributeList = []; - var attribute = { - Name : 'nickname', - Value : 'joe' - }; - var attribute = new AmazonCognitoIdentity.CognitoUserAttribute(attribute); - attributeList.push(attribute); - - cognitoUser.updateAttributes(attributeList, function(err, result) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('call result: ' + result); - }); +var attributeList = []; +var attribute = { + Name: 'nickname', + Value: 'joe', +}; +var attribute = new AmazonCognitoIdentity.CognitoUserAttribute(attribute); +attributeList.push(attribute); + +cognitoUser.updateAttributes(attributeList, function(err, result) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('call result: ' + result); +}); ``` **Use case 9.** Enabling MFA for a user on a pool that has an optional MFA setting for an authenticated user. @@ -407,13 +419,13 @@ Note that the inputVerificationCode method needs to be defined but does not need Note: this method is now deprecated. Please use `setUserMfaPreference` instead. ```javascript - cognitoUser.enableMFA(function(err, result) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('call result: ' + result); - }); +cognitoUser.enableMFA(function(err, result) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('call result: ' + result); +}); ``` **Use case 10.** Disabling MFA for a user on a pool that has an optional MFA setting for an authenticated user. @@ -421,30 +433,31 @@ Note: this method is now deprecated. Please use `setUserMfaPreference` instead. Note: this method is now deprecated. Please use `setUserMfaPreference` instead. ```javascript - cognitoUser.disableMFA(function(err, result) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('call result: ' + result); - }); +cognitoUser.disableMFA(function(err, result) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('call result: ' + result); +}); ``` **Use case 11.** Changing the current password for an authenticated user. ```javascript - cognitoUser.changePassword('oldPassword', 'newPassword', function(err, result) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('call result: ' + result); - }); +cognitoUser.changePassword('oldPassword', 'newPassword', function(err, result) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('call result: ' + result); +}); ``` **Use case 12.** Starting and completing a forgot password flow for an unauthenticated user. -For example: +For example: + ```html @@ -457,55 +470,53 @@ For example: ``` ```javascript - cognitoUser.forgotPassword({ - onSuccess: function (data) { - // successfully initiated reset password request - console.log('CodeDeliveryData from forgotPassword: ' + data); - }, - onFailure: function(err) { - alert(err.message || JSON.stringify(err)); - }, - //Optional automatic callback - inputVerificationCode: function(data) { - console.log('Code sent to: ' + data); - var code = document.getElementById('code').value; - var newPassword = document.getElementById('new_password').value; - cognitoUser.confirmPassword(verificationCode, newPassword, { - onSuccess() { - console.log('Password confirmed!'); - }, - onFailure(err) { - console.log('Password not confirmed!'); - } - }); - } - }); +cognitoUser.forgotPassword({ + onSuccess: function(data) { + // successfully initiated reset password request + console.log('CodeDeliveryData from forgotPassword: ' + data); + }, + onFailure: function(err) { + alert(err.message || JSON.stringify(err)); + }, + //Optional automatic callback + inputVerificationCode: function(data) { + console.log('Code sent to: ' + data); + var code = document.getElementById('code').value; + var newPassword = document.getElementById('new_password').value; + cognitoUser.confirmPassword(verificationCode, newPassword, { + onSuccess() { + console.log('Password confirmed!'); + }, + onFailure(err) { + console.log('Password not confirmed!'); + }, + }); + }, +}); ``` - - **Use case 13.** Deleting an authenticated user. ```javascript - cognitoUser.deleteUser(function(err, result) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('call result: ' + result); - }); +cognitoUser.deleteUser(function(err, result) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('call result: ' + result); +}); ``` **Use case 14.** Signing out from the application. ```javascript - cognitoUser.signOut(); +cognitoUser.signOut(); ``` **Use case 15.** Global signout for an authenticated user(invalidates all issued tokens). ```javascript - cognitoUser.globalSignOut(callback); +cognitoUser.globalSignOut(callback); ``` **Use case 16 with React Native.** @@ -513,178 +524,174 @@ For example: In React Native, loading the persisted current user information requires an extra async call to be made: ```javascript - var poolData = { - UserPoolId : '...', // Your user pool id here - ClientId : '...' // Your client id here - }; - var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); - - userPool.storage.sync(function(err, result) { - if (err) { } - else if (result === 'SUCCESS') { - var cognitoUser = userPool.getCurrentUser(); - // Continue with steps in Use case 16 - } - }); +var poolData = { + UserPoolId: '...', // Your user pool id here + ClientId: '...', // Your client id here +}; +var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); + +userPool.storage.sync(function(err, result) { + if (err) { + } else if (result === 'SUCCESS') { + var cognitoUser = userPool.getCurrentUser(); + // Continue with steps in Use case 16 + } +}); ``` **Use case 16.** Retrieving the current user from local storage. ```javascript - var poolData = { - UserPoolId : '...', // Your user pool id here - ClientId : '...' // Your client id here - }; - var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); - var cognitoUser = userPool.getCurrentUser(); - - if (cognitoUser != null) { - cognitoUser.getSession(function(err, session) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('session validity: ' + session.isValid()); - - // NOTE: getSession must be called to authenticate user before calling getUserAttributes - cognitoUser.getUserAttributes(function(err, attributes) { - if (err) { - // Handle error - } else { - // Do something with attributes - } - }); - - AWS.config.credentials = new AWS.CognitoIdentityCredentials({ - IdentityPoolId : '...', // your identity pool id here - Logins : { - // Change the key below according to the specific region your user pool is in. - 'cognito-idp..amazonaws.com/' : session.getIdToken().getJwtToken() - } - }); - - // Instantiate aws sdk service objects now that the credentials have been updated. - // example: var s3 = new AWS.S3(); - - }); - } +var poolData = { + UserPoolId: '...', // Your user pool id here + ClientId: '...', // Your client id here +}; +var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); +var cognitoUser = userPool.getCurrentUser(); + +if (cognitoUser != null) { + cognitoUser.getSession(function(err, session) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('session validity: ' + session.isValid()); + + // NOTE: getSession must be called to authenticate user before calling getUserAttributes + cognitoUser.getUserAttributes(function(err, attributes) { + if (err) { + // Handle error + } else { + // Do something with attributes + } + }); + + AWS.config.credentials = new AWS.CognitoIdentityCredentials({ + IdentityPoolId: '...', // your identity pool id here + Logins: { + // Change the key below according to the specific region your user pool is in. + 'cognito-idp..amazonaws.com/': session + .getIdToken() + .getJwtToken(), + }, + }); + + // Instantiate aws sdk service objects now that the credentials have been updated. + // example: var s3 = new AWS.S3(); + }); +} ``` **Use case 17.** Integrating User Pools with Cognito Identity. ```javascript - var cognitoUser = userPool.getCurrentUser(); - - if (cognitoUser != null) { - cognitoUser.getSession(function(err, result) { - if (result) { - console.log('You are now logged in.'); - - //POTENTIAL: Region needs to be set if not already set previously elsewhere. - AWS.config.region = ''; - - // Add the User's Id Token to the Cognito credentials login map. - AWS.config.credentials = new AWS.CognitoIdentityCredentials({ - IdentityPoolId: 'YOUR_IDENTITY_POOL_ID', - Logins: { - 'cognito-idp..amazonaws.com/': result.getIdToken().getJwtToken() - } - }); - } - }); - } - //call refresh method in order to authenticate user and get new temp credentials - AWS.config.credentials.refresh((error) => { - if (error) { - console.error(error); - } else { - console.log('Successfully logged!'); - } - }); +var cognitoUser = userPool.getCurrentUser(); + +if (cognitoUser != null) { + cognitoUser.getSession(function(err, result) { + if (result) { + console.log('You are now logged in.'); + + //POTENTIAL: Region needs to be set if not already set previously elsewhere. + AWS.config.region = ''; + + // Add the User's Id Token to the Cognito credentials login map. + AWS.config.credentials = new AWS.CognitoIdentityCredentials({ + IdentityPoolId: 'YOUR_IDENTITY_POOL_ID', + Logins: { + 'cognito-idp..amazonaws.com/': result + .getIdToken() + .getJwtToken(), + }, + }); + } + }); +} +//call refresh method in order to authenticate user and get new temp credentials +AWS.config.credentials.refresh(error => { + if (error) { + console.error(error); + } else { + console.log('Successfully logged!'); + } +}); ``` -*note that you can not replace the login key with a variable because it will be interpreted literally. if you want to use a variable, the resolution to [issue 17](https://github.com/aws/amazon-cognito-identity-js/issues/162) has a working example* + +_note that you can not replace the login key with a variable because it will be interpreted literally. if you want to use a variable, the resolution to [issue 17](https://github.com/aws/amazon-cognito-identity-js/issues/162) has a working example_ **Use case 18.** List all remembered devices for an authenticated user. In this case, we need to pass a limit on the number of devices retrieved at a time and a pagination token is returned to make subsequent calls. The pagination token can be subsequently passed. When making the first call, the pagination token should be null. ```javascript - - cognitoUser.listDevices(limit, paginationToken, { - onSuccess: function (result) { - console.log('call result: ' + result); - }, - onFailure: function(err) { - alert(err.message); - } - }); - +cognitoUser.listDevices(limit, paginationToken, { + onSuccess: function(result) { + console.log('call result: ' + result); + }, + onFailure: function(err) { + alert(err.message); + }, +}); ``` **Use case 19.** List information about the current device. ```javascript - - cognitoUser.getDevice({ - onSuccess: function (result) { - console.log('call result: ' + result); - }, - onFailure: function(err) { - alert(err.message || JSON.stringify(err)); - } - }); +cognitoUser.getDevice({ + onSuccess: function(result) { + console.log('call result: ' + result); + }, + onFailure: function(err) { + alert(err.message || JSON.stringify(err)); + }, +}); ``` - **Use case 20.** Remember a device. ```javascript - - cognitoUser.setDeviceStatusRemembered({ - onSuccess: function (result) { - console.log('call result: ' + result); - }, - onFailure: function(err) { - alert(err.message || JSON.stringify(err)); - } - }); +cognitoUser.setDeviceStatusRemembered({ + onSuccess: function(result) { + console.log('call result: ' + result); + }, + onFailure: function(err) { + alert(err.message || JSON.stringify(err)); + }, +}); ``` **Use case 21.** Do not remember a device. ```javascript - - cognitoUser.setDeviceStatusNotRemembered({ - onSuccess: function (result) { - console.log('call result: ' + result); - }, - onFailure: function(err) { - alert(err.message || JSON.stringify(err)); - } - }); +cognitoUser.setDeviceStatusNotRemembered({ + onSuccess: function(result) { + console.log('call result: ' + result); + }, + onFailure: function(err) { + alert(err.message || JSON.stringify(err)); + }, +}); ``` - **Use case 22.** Forget the current device. ```javascript - - cognitoUser.forgetDevice({ - onSuccess: function (result) { - console.log('call result: ' + result); - }, - onFailure: function(err) { - alert(err.message || JSON.stringify(err)); - } - }); +cognitoUser.forgetDevice({ + onSuccess: function(result) { + console.log('call result: ' + result); + }, + onFailure: function(err) { + alert(err.message || JSON.stringify(err)); + }, +}); ``` **Use case 23.** Authenticate a user and set new password for a user that was created using AdminCreateUser API. ```javascript - + var cognitoUser, sessionUserAttributes; // global variables to handle completeNewPasswordChallenge flow - + // ... - + cognitoUser.authenticateUser(authenticationDetails, { onSuccess: function (result) { // User authentication was successful @@ -707,48 +714,49 @@ In React Native, loading the persisted current user information requires an extr // the api doesn't accept this field back delete userAttributes.email_verified; - + // store userAttributes on global variable sessionUserAttributes = userAttributes; } }); - + // ... handle new password flow on your app handleNewPassword(newPassword) { cognitoUser.completeNewPasswordChallenge(newPassword, sessionUserAttributes); } - + ``` + **Use case 24.** Retrieve the MFA Options for the user in case MFA is optional. ```javascript - cognitoUser.getMFAOptions(function(err, mfaOptions) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('MFA options for user ' + mfaOptions); - }); +cognitoUser.getMFAOptions(function(err, mfaOptions) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('MFA options for user ' + mfaOptions); +}); ``` **Use case 25.** Authenticating a user with a passwordless custom flow. ```javascript - cognitoUser.setAuthenticationFlowType('CUSTOM_AUTH'); - - cognitoUser.initiateAuth(authenticationDetails, { - onSuccess: function(result) { - // User authentication was successful - }, - onFailure: function(err) { - // User authentication was not successful - }, - customChallenge: function(challengeParameters) { - // User authentication depends on challenge response - var challengeResponses = 'challenge-answer' - cognitoUser.sendCustomChallengeAnswer(challengeResponses, this); - } - }); +cognitoUser.setAuthenticationFlowType('CUSTOM_AUTH'); + +cognitoUser.initiateAuth(authenticationDetails, { + onSuccess: function(result) { + // User authentication was successful + }, + onFailure: function(err) { + // User authentication was not successful + }, + customChallenge: function(challengeParameters) { + // User authentication depends on challenge response + var challengeResponses = 'challenge-answer'; + cognitoUser.sendCustomChallengeAnswer(challengeResponses, this); + }, +}); ``` **Use case 26.** Using cookies to store cognito tokens @@ -758,183 +766,192 @@ In React Native, loading the persisted current user information requires an extr To use the CookieStorage you have to pass it in the constructor map of CognitoUserPool and CognitoUser (when constructed directly): - ```js - var poolData = { - UserPoolId : '...', // Your user pool id here - ClientId : '...' // Your client id here - Storage: new AmazonCognitoIdentity.CookieStorage({domain: ".yourdomain.com"}) - }; +```js + var poolData = { + UserPoolId : '...', // Your user pool id here + ClientId : '...' // Your client id here + Storage: new AmazonCognitoIdentity.CookieStorage({domain: ".yourdomain.com"}) + }; - var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); + var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); + + var userData = { + Username: 'username', + Pool: userPool, + Storage: new AmazonCognitoIdentity.CookieStorage({domain: ".yourdomain.com"}) + }; +``` - var userData = { - Username: 'username', - Pool: userPool, - Storage: new AmazonCognitoIdentity.CookieStorage({domain: ".yourdomain.com"}) - }; - ``` The CookieStorage object receives a map (data) in its constructor that may have these values: - * data.domain Cookies domain (mandatory) - * data.path Cookies path (default: '/') - * data.expires Cookie expiration (in days, default: 365) - * data.secure Cookie secure flag (default: true) + +- data.domain Cookies domain (mandatory) +- data.path Cookies path (default: '/') +- data.expires Cookie expiration (in days, default: 365) +- data.secure Cookie secure flag (default: true) **Use case 27.** Selecting the MFA method and authenticating using TOTP. - ```js - var authenticationData = { - Username : 'username', - Password : 'password', - }; - var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData); - var poolData = { - UserPoolId : '...', // Your user pool id here - ClientId : '...' // Your client id here - }; - var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); - var userData = { - Username : 'username', - Pool : userPool - }; - var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData); - - cognitoUser.authenticateUser(authenticationDetails, { - onSuccess: function (result) { - var accessToken = result.getAccessToken().getJwtToken(); - }, - - onFailure: function(err) { - alert(err.message || JSON.stringify(err)); - }, - - mfaSetup: function(challengeName, challengeParameters) { - cognitoUser.associateSoftwareToken(this); - }, - - associateSecretCode : function(secretCode) { - var challengeAnswer = prompt('Please input the TOTP code.' ,''); - cognitoUser.verifySoftwareToken(challengeAnswer, 'My TOTP device', this); - }, - - selectMFAType : function(challengeName, challengeParameters) { - var mfaType = prompt('Please select the MFA method.', ''); // valid values for mfaType is "SMS_MFA", "SOFTWARE_TOKEN_MFA" - cognitoUser.sendMFASelectionAnswer(mfaType, this); - }, - - totpRequired : function(secretCode) { - var challengeAnswer = prompt('Please input the TOTP code.' ,''); - cognitoUser.sendMFACode(challengeAnswer, this, 'SOFTWARE_TOKEN_MFA'); - }, - - mfaRequired: function(codeDeliveryDetails) { - var verificationCode = prompt('Please input verification code' ,''); - cognitoUser.sendMFACode(verificationCode, this); - } - }); - ``` +```js +var authenticationData = { + Username: 'username', + Password: 'password', +}; +var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails( + authenticationData +); +var poolData = { + UserPoolId: '...', // Your user pool id here + ClientId: '...', // Your client id here +}; +var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); +var userData = { + Username: 'username', + Pool: userPool, +}; +var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData); + +cognitoUser.authenticateUser(authenticationDetails, { + onSuccess: function(result) { + var accessToken = result.getAccessToken().getJwtToken(); + }, + + onFailure: function(err) { + alert(err.message || JSON.stringify(err)); + }, + + mfaSetup: function(challengeName, challengeParameters) { + cognitoUser.associateSoftwareToken(this); + }, + + associateSecretCode: function(secretCode) { + var challengeAnswer = prompt('Please input the TOTP code.', ''); + cognitoUser.verifySoftwareToken(challengeAnswer, 'My TOTP device', this); + }, + + selectMFAType: function(challengeName, challengeParameters) { + var mfaType = prompt('Please select the MFA method.', ''); // valid values for mfaType is "SMS_MFA", "SOFTWARE_TOKEN_MFA" + cognitoUser.sendMFASelectionAnswer(mfaType, this); + }, + + totpRequired: function(secretCode) { + var challengeAnswer = prompt('Please input the TOTP code.', ''); + cognitoUser.sendMFACode(challengeAnswer, this, 'SOFTWARE_TOKEN_MFA'); + }, + + mfaRequired: function(codeDeliveryDetails) { + var verificationCode = prompt('Please input verification code', ''); + cognitoUser.sendMFACode(verificationCode, this); + }, +}); +``` **Use case 28.** Enabling and setting SMS MFA as the preferred MFA method for the user. - ```js - smsMfaSettings = { - PreferredMfa : true, - Enabled : true - }; - cognitoUser.setUserMfaPreference(smsMfaSettings, null, function(err, result) { - if (err) { - alert(err.message || JSON.stringify(err)); - } - console.log('call result ' + result) - }); - ``` +```js +smsMfaSettings = { + PreferredMfa: true, + Enabled: true, +}; +cognitoUser.setUserMfaPreference(smsMfaSettings, null, function(err, result) { + if (err) { + alert(err.message || JSON.stringify(err)); + } + console.log('call result ' + result); +}); +``` **Use case 29.** Enabling and setting TOTP MFA as the preferred MFA method for the user. - ```js - totpMfaSettings = { - PreferredMfa : true, - Enabled : true - }; - cognitoUser.setUserMfaPreference(null, totpMfaSettings, function(err, result) { - if (err) { - alert(err.message || JSON.stringify(err)); - } - console.log('call result ' + result) - }); - ``` - -**Use case 30.** Authenticating a user with a user password auth flow. +```js +totpMfaSettings = { + PreferredMfa: true, + Enabled: true, +}; +cognitoUser.setUserMfaPreference(null, totpMfaSettings, function(err, result) { + if (err) { + alert(err.message || JSON.stringify(err)); + } + console.log('call result ' + result); +}); +``` - ```js - cognitoUser.setAuthenticationFlowType('USER_PASSWORD_AUTH'); - - cognitoUser.authenticateUser(authenticationDetails, { - onSuccess: function(result) { - // User authentication was successful - }, - onFailure: function(err) { - // User authentication was not successful - }, - mfaRequired: function (codeDeliveryDetails) { - // MFA is required to complete user authentication. - // Get the code from user and call - cognitoUser.sendMFACode(verificationCode, this); - } - }); - ``` - -**Use case 31.** Retrieve the user data for an authenticated user. +**Use case 30.** Authenticating a user with a user password auth flow. + +```js +cognitoUser.setAuthenticationFlowType('USER_PASSWORD_AUTH'); + +cognitoUser.authenticateUser(authenticationDetails, { + onSuccess: function(result) { + // User authentication was successful + }, + onFailure: function(err) { + // User authentication was not successful + }, + mfaRequired: function(codeDeliveryDetails) { + // MFA is required to complete user authentication. + // Get the code from user and call + cognitoUser.sendMFACode(verificationCode, this); + }, +}); +``` - ```js - cognitoUser.getUserData(function(err, userData) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('User data for user ' + userData); - }); - - // If you want to force to get the user data from backend, - // you can set the bypassCache to true - cognitoUser.getUserData(function(err, userData) { - if (err) { - alert(err.message || JSON.stringify(err)); - return; - } - console.log('User data for user ' + userData); - }, {bypassCache: true}); - ``` +**Use case 31.** Retrieve the user data for an authenticated user. -**Use case 32.** Handling expiration of the Id Token. +```js +cognitoUser.getUserData(function(err, userData) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('User data for user ' + userData); +}); + +// If you want to force to get the user data from backend, +// you can set the bypassCache to true +cognitoUser.getUserData( + function(err, userData) { + if (err) { + alert(err.message || JSON.stringify(err)); + return; + } + console.log('User data for user ' + userData); + }, + { bypassCache: true } +); +``` - ```js - refresh_token = session.getRefreshToken(); // receive session from calling cognitoUser.getSession() - if (AWS.config.credentials.needsRefresh()) { - cognitoUser.refreshSession(refresh_token, (err, session) => { - if(err) { - console.log(err); - } - else { - AWS.config.credentials.params.Logins['cognito-idp..amazonaws.com/'] = session.getIdToken().getJwtToken(); - AWS.config.credentials.refresh((err)=> { - if(err) { - console.log(err); - } - else{ - console.log("TOKEN SUCCESSFULLY UPDATED"); - } - }); - } - }); - } - ``` +**Use case 32.** Handling expiration of the Id Token. + +```js +refresh_token = session.getRefreshToken(); // receive session from calling cognitoUser.getSession() +if (AWS.config.credentials.needsRefresh()) { + cognitoUser.refreshSession(refresh_token, (err, session) => { + if (err) { + console.log(err); + } else { + AWS.config.credentials.params.Logins[ + 'cognito-idp..amazonaws.com/' + ] = session.getIdToken().getJwtToken(); + AWS.config.credentials.refresh(err => { + if (err) { + console.log(err); + } else { + console.log('TOKEN SUCCESSFULLY UPDATED'); + } + }); + } + }); +} +``` ## Network Configuration + The Amazon Cognito Identity JavaScript SDK will make requests to the following endpoints -* For Amazon Cognito User Pool service request handling: "https://cognito-idp.us-east-1.amazonaws.com" - * This endpoint may change based on which region your Cognito User Pool was created in. -For most frameworks you can whitelist the domain by whitelisting all AWS endpoints with "*.amazonaws.com". +- For Amazon Cognito User Pool service request handling: "https://cognito-idp.us-east-1.amazonaws.com" + - This endpoint may change based on which region your Cognito User Pool was created in. + +For most frameworks you can whitelist the domain by whitelisting all AWS endpoints with "\*.amazonaws.com". ## Random numbers @@ -945,134 +962,165 @@ In order to authenticate with the Amazon Cognito User Pool Service, the client n Latest change logs have been moved to [CHANGELOG.md](./CHANGELOG.md). **v2.0.2:** -* What has changed - * To make a new version for NPM package sync with Github repo. + +- What has changed + - To make a new version for NPM package sync with Github repo. **v2.0.1:** -* What has changed - * Added migration lambda trigger support. + +- What has changed + - Added migration lambda trigger support. **v1.31.0:** -* What has changed - * Added lib folder. + +- What has changed + - Added lib folder. **v1.30.0:** -* What has changed - * Temporary fix to lock down the AWS SDK version to a compatible one. - + +- What has changed + + - Temporary fix to lock down the AWS SDK version to a compatible one. + **v1.29.0:** -* What has changed - * Fixing verify software token call to work with access token. + +- What has changed + - Fixing verify software token call to work with access token. **v1.28.0:** -* What has changed - * Not sending UserContextData if it is not available. + +- What has changed + - Not sending UserContextData if it is not available. **v1.27.0:** -* What has changed - * Added support for TOTP and new MFA settings APIs. + +- What has changed + - Added support for TOTP and new MFA settings APIs. **v1.26.0:** -* What has changed - * Fixed typescript typings. + +- What has changed + - Fixed typescript typings. **v1.25.0:** -* What has changed - * Added cookie storage support and solved bug related to clock drift parsing. + +- What has changed + - Added cookie storage support and solved bug related to clock drift parsing. **v1.24.0:** -* What has changed - * Fixed bug related to missing callback + +- What has changed + - Fixed bug related to missing callback **v1.23.0:** -* What has changed - * Added react native optimizations for BigInteger + +- What has changed + - Added react native optimizations for BigInteger **v1.19.0:** -* What has changed - * Added UserSub return on sign up + +- What has changed + - Added UserSub return on sign up **v1.18.0:** -* What has changed - * Added missing result in resendConfirmationCode. + +- What has changed + - Added missing result in resendConfirmationCode. **v1.17.0:** -* What has changed - * Added non-minified files. + +- What has changed + - Added non-minified files. **v1.16.0:** -* What has changed - * Brought in JSBN and updated Notice file. + +- What has changed + - Brought in JSBN and updated Notice file. **v1.15.0:** -* What has changed - * Solved an issue that occurred rarely related to the padding of the U value that is used in computing the HKDF. + +- What has changed + - Solved an issue that occurred rarely related to the padding of the U value that is used in computing the HKDF. **v1.14.0:** -* What has changed - * Importing only the CognitoIdentityServiceProvider client and util from the AWS SDK. + +- What has changed + - Importing only the CognitoIdentityServiceProvider client and util from the AWS SDK. **v1.13.0:** -* What has changed - * Removed SJCL as a dependency and fixed typescript typings. + +- What has changed + - Removed SJCL as a dependency and fixed typescript typings. **v1.12.0:** -* What has changed - * Added typescript typings. + +- What has changed + - Added typescript typings. **v1.11.0:** -* What has changed - * Added challenge parameters to the mfaRequired function of the return object. + +- What has changed + - Added challenge parameters to the mfaRequired function of the return object. **v1.10.0:** -* What has changed - * Clearing tokens when they have been revoked and adding retrieval for MFAOptions. + +- What has changed + - Clearing tokens when they have been revoked and adding retrieval for MFAOptions. **v1.9.0:** -* What has changed - * Fixed dependency on local storage. Reverting to memory use when local storage is not available. + +- What has changed + - Fixed dependency on local storage. Reverting to memory use when local storage is not available. **v1.7.0:** -* What has changed - * Fixed Cannot read property 'NewDeviceMetadata' of undefined bug. + +- What has changed + - Fixed Cannot read property 'NewDeviceMetadata' of undefined bug. **v1.6.0:** -* What has changed - * Support for Admin create user flow. Users being signed up by admins will be able to authenticate using their one time passwords. + +- What has changed + - Support for Admin create user flow. Users being signed up by admins will be able to authenticate using their one time passwords. **v1.5.0:** -* What has changed - * Changed webpack support to follow AWS-SDK usage. + +- What has changed + - Changed webpack support to follow AWS-SDK usage. **v1.2.0:** -* What has changed - * Derived the region from the user pool id so the region doesn't need to be configured anymore. + +- What has changed + - Derived the region from the user pool id so the region doesn't need to be configured anymore. **v1.1.0:** -* What has changed - * Fixed a bug in token parsing. - * Removed moment.js as a dependency. + +- What has changed + - Fixed a bug in token parsing. + - Removed moment.js as a dependency. **v1.0.0:** -* GA release. In this GA service launch, the following new features have been added to Amazon Cognito Your User Pools. - -* Whats new - * Webpack support. - * Support for Custom authentication flows. Developers can implement custom authentication flows around Cognito Your User Pools. See developer documentation for details. - * Devices support in User Pools. Users can remember devices and skip MFA verification for remembered devices. - * Scopes to control permissions for attributes in a User Pool. - * Configurable expiration time for refresh tokens. - * Set custom FROM and REPLY-TO for email verification messages. - * Search users in your pool using user attributes. - * Global sign-out for a user. - * Removed dependency to sjcl bytes codec. - -* What has changed - * Authentication flow in Javascript SDK now uses Custom Authentication API - * Two new exceptions added for the authentication APIs: These exceptions have been added to accurately represent the user state when the username is invalid and when the user is not confirmed. You will have to update your application to handle these exceptions. - * UserNotFoundException: Returned when the username user does not exist. - * UserNotConfirmedException: Returned when the user has not been confirmed. - * PasswordResetRequiredException: When administrator has requested for a password reset for the user. + +- GA release. In this GA service launch, the following new features have been added to Amazon Cognito Your User Pools. + +- Whats new + + - Webpack support. + - Support for Custom authentication flows. Developers can implement custom authentication flows around Cognito Your User Pools. See developer documentation for details. + - Devices support in User Pools. Users can remember devices and skip MFA verification for remembered devices. + - Scopes to control permissions for attributes in a User Pool. + - Configurable expiration time for refresh tokens. + - Set custom FROM and REPLY-TO for email verification messages. + - Search users in your pool using user attributes. + - Global sign-out for a user. + - Removed dependency to sjcl bytes codec. + +- What has changed + - Authentication flow in Javascript SDK now uses Custom Authentication API + - Two new exceptions added for the authentication APIs: These exceptions have been added to accurately represent the user state when the username is invalid and when the user is not confirmed. You will have to update your application to handle these exceptions. + - UserNotFoundException: Returned when the username user does not exist. + - UserNotConfirmedException: Returned when the user has not been confirmed. + - PasswordResetRequiredException: When administrator has requested for a password reset for the user. **v0.9.0:** -* Initial release. Developer preview. + +- Initial release. Developer preview. diff --git a/packages/amazon-cognito-identity-js/enhance-rn.js b/packages/amazon-cognito-identity-js/enhance-rn.js index 8956b9d39ac..35d8eafb639 100644 --- a/packages/amazon-cognito-identity-js/enhance-rn.js +++ b/packages/amazon-cognito-identity-js/enhance-rn.js @@ -2,7 +2,7 @@ import { NativeModules } from 'react-native'; import * as src from './src'; import UserAgent from './src/UserAgent'; -UserAgent.prototype.userAgent = 'aws-amplify/0.1.x react-native' +UserAgent.prototype.userAgent = 'aws-amplify/0.1.x react-native'; import BigInteger from './src/BigInteger'; @@ -11,34 +11,43 @@ export * from './src'; const { RNAWSCognito } = NativeModules; BigInteger.prototype.modPow = function nativeModPow(e, m, callback) { - RNAWSCognito.computeModPow({ - target: this.toString(16), - value: e.toString(16), - modifier: m.toString(16), - }, (err, result) => { - if (err) { - return callback(new Error(err), null); - } - const bigIntResult = new BigInteger(result, 16); - return callback(null, bigIntResult); - }); + RNAWSCognito.computeModPow( + { + target: this.toString(16), + value: e.toString(16), + modifier: m.toString(16), + }, + (err, result) => { + if (err) { + return callback(new Error(err), null); + } + const bigIntResult = new BigInteger(result, 16); + return callback(null, bigIntResult); + } + ); }; -src.AuthenticationHelper.prototype.calculateS = -function nativeComputeS(xValue, serverBValue, callback) { - RNAWSCognito.computeS({ - g: this.g.toString(16), - x: xValue.toString(16), - k: this.k.toString(16), - a: this.smallAValue.toString(16), - b: serverBValue.toString(16), - u: this.UValue.toString(16), - }, (err, result) => { - if (err) { - return callback(new Error(err), null); - } - const bigIntResult = new BigInteger(result, 16); - return callback(null, bigIntResult); - }); - return undefined; +src.AuthenticationHelper.prototype.calculateS = function nativeComputeS( + xValue, + serverBValue, + callback +) { + RNAWSCognito.computeS( + { + g: this.g.toString(16), + x: xValue.toString(16), + k: this.k.toString(16), + a: this.smallAValue.toString(16), + b: serverBValue.toString(16), + u: this.UValue.toString(16), + }, + (err, result) => { + if (err) { + return callback(new Error(err), null); + } + const bigIntResult = new BigInteger(result, 16); + return callback(null, bigIntResult); + } + ); + return undefined; }; diff --git a/packages/amazon-cognito-identity-js/index.d.ts b/packages/amazon-cognito-identity-js/index.d.ts index e6dcb7359c6..707055e551d 100644 --- a/packages/amazon-cognito-identity-js/index.d.ts +++ b/packages/amazon-cognito-identity-js/index.d.ts @@ -1,236 +1,364 @@ -declare module "amazon-cognito-identity-js" { - - //import * as AWS from "aws-sdk"; - - export type NodeCallback = (err?: E, result?: T) => void; - - - export interface CodeDeliveryDetails { - AttributeName: string, - DeliveryMedium: string, - Destination: string - } - - export interface IAuthenticationCallback { - onSuccess: (session: CognitoUserSession, userConfirmationNecessary?: boolean) => void, - onFailure: (err: any) => void, - newPasswordRequired?: (userAttributes: any, requiredAttributes: any) => void, - mfaRequired?: (challengeName: any, challengeParameters: any) => void, - totpRequired?: (challengeName: any, challengeParameters: any) => void, - customChallenge?: (challengeParameters: any) => void, - mfaSetup?: (challengeName: any, challengeParameters: any) => void, - selectMFAType?: (challengeName: any, challengeParameters: any) => void - } - - export interface IMfaSettings { - PreferredMfa: boolean, - Enabled: boolean - } - export interface IAuthenticationDetailsData { - Username: string; - Password?: string; - ValidationData?: {[key: string]: any} - } - - export class AuthenticationDetails { - constructor(data: IAuthenticationDetailsData); - - public getUsername(): string; - public getPassword(): string; - public getValidationData(): any[]; - } - - export interface ICognitoStorage { - setItem(key: string, value: string): void; - getItem(key: string): string; - removeItem(key: string): void; - clear(): void; - } - - export interface ICognitoUserData { - Username: string; - Pool: CognitoUserPool; - Storage?: ICognitoStorage; - } - - export class CognitoUser { - constructor(data: ICognitoUserData); - - public setSignInUserSession(signInUserSession: CognitoUserSession): void; - public getSignInUserSession(): CognitoUserSession | null; - public getUsername(): string; - - public getAuthenticationFlowType(): string; - public setAuthenticationFlowType(authenticationFlowType: string): string; - - public getSession(callback: Function): any; - public refreshSession(refreshToken: CognitoRefreshToken, callback: NodeCallback): void; - public authenticateUser(authenticationDetails: AuthenticationDetails, - callbacks: IAuthenticationCallback): void; - public initiateAuth(authenticationDetails: AuthenticationDetails, - callbacks: IAuthenticationCallback): void; - public confirmRegistration(code: string, forceAliasCreation: boolean, callback: NodeCallback): void; - public sendCustomChallengeAnswer(answerChallenge: any, callback:IAuthenticationCallback):void; - public resendConfirmationCode(callback: NodeCallback): void; - public changePassword(oldPassword: string, newPassword: string, callback: NodeCallback): void; - public forgotPassword(callbacks: { onSuccess: (data: any) => void, onFailure: (err: Error) => void, inputVerificationCode?: (data: any) => void }): void; - public confirmPassword(verificationCode: string, newPassword: string, callbacks: { onSuccess: () => void, onFailure: (err: Error) => void }): void; - public setDeviceStatusRemembered(callbacks: { onSuccess: (success: string) => void, onFailure: (err: any) => void }): void; - public setDeviceStatusNotRemembered(callbacks: { onSuccess: (success: string) => void, onFailure: (err: any) => void }): void; - public getDevice(callbacks: {onSuccess: (success: string) => void, onFailure: (err: Error) => void}): any; - public forgetDevice(callbacks: {onSuccess: (success: string) => void, onFailure: (err: Error) => void}): void; - public forgetSpecificDevice(deviceKey: string, callbacks: {onSuccess: (success: string) => void, onFailure: (err: Error) => void}): void; - public sendMFACode(confirmationCode: string, callbacks: { onSuccess: (session: CognitoUserSession) => void, onFailure: (err: any) => void }, mfaType?: string): void; - public listDevices(limit: number, paginationToken: string, callbacks: {onSuccess: (data: any) => void, onFailure: (err: Error) => void}): void; - public completeNewPasswordChallenge(newPassword: string, - requiredAttributeData: any, - callbacks: { - onSuccess: (session: CognitoUserSession) => void, - onFailure: (err: any) => void, - mfaRequired?: (challengeName: any, challengeParameters: any) => void, - customChallenge?: (challengeParameters: any) => void, - mfaSetup?: (challengeName: any, challengeParameters: any) => void - }): void; - public signOut(): void; - public globalSignOut(callbacks: { onSuccess: (msg: string) => void, onFailure: (err: Error) => void }): void; - public verifyAttribute(attributeName: string, confirmationCode: string, callbacks: { onSuccess: (success: string) => void, onFailure: (err: Error) => void }): void; - public getUserAttributes(callback: NodeCallback): void; - public updateAttributes(attributes: ICognitoUserAttributeData[], callback: NodeCallback): void; - public deleteAttributes(attributeList: string[], callback: NodeCallback): void; - public getAttributeVerificationCode(name: string, callback: { onSuccess: () => void, onFailure: (err: Error) => void, inputVerificationCode?: (data: string) => void | null }): void; - public deleteUser(callback: NodeCallback): void; - public enableMFA(callback: NodeCallback): void; - public disableMFA(callback: NodeCallback): void; - public getMFAOptions(callback: NodeCallback): void; - public getUserData(callback: NodeCallback): void; - public associateSoftwareToken( - callbacks: { - associateSecretCode: (secretCode: string) => void, - onFailure: (err: any) => void - }): void; - public verifySoftwareToken(totpCode: string, friendlyDeviceName: string, callbacks: {onSuccess: (session: CognitoUserSession) => void, onFailure: (err: Error) => void}): void; - public setUserMfaPreference(smsMfaSettings: IMfaSettings | null, softwareTokenMfaSettings: IMfaSettings | null, callback: NodeCallback): void; - public sendMFASelectionAnswer(answerChallenge: string, - callbacks: { - onSuccess: (session: CognitoUserSession) => void, - onFailure: (err: any) => void, - mfaRequired?: (challengeName: any, challengeParameters: any) => void, - totpRequired?: (challengeName: any, challengeParameters: any) => void - }): void; - } - - export interface MFAOption { - DeliveryMedium: "SMS" |"EMAIL"; - AttributeName: string; - } - - export interface UserData { - MFAOptions: MFAOption[]; - PreferredMfaSetting: string; - UserAttributes: ICognitoUserAttributeData[]; - UserMFASettingList: string[]; - Username: string; - } - - export interface ICognitoUserAttributeData { - Name: string; - Value: string; - } - - export class CognitoUserAttribute { - constructor(data: ICognitoUserAttributeData); - - public getValue(): string; - public setValue(value: string): CognitoUserAttribute; - public getName(): string; - public setName(name: string): CognitoUserAttribute; - public toString(): string; - public toJSON(): Object; - } - - export interface ISignUpResult { - user: CognitoUser; - userConfirmed: boolean; - userSub: string; - codeDeliveryDetails: CodeDeliveryDetails - } - - export interface ICognitoUserPoolData { - UserPoolId: string; - ClientId: string; - endpoint?: string; - Storage?: ICognitoStorage; - } - - export class CognitoUserPool { - constructor(data: ICognitoUserPoolData); - - public getUserPoolId(): string; - public getClientId(): string; - - public signUp(username: string, password: string, userAttributes: CognitoUserAttribute[], validationData: CognitoUserAttribute[], callback: NodeCallback): void; - - public getCurrentUser(): CognitoUser | null; - } - - export interface ICognitoUserSessionData { - IdToken: CognitoIdToken; - AccessToken: CognitoAccessToken; - RefreshToken?: CognitoRefreshToken; - } - - export class CognitoUserSession { - constructor(data: ICognitoUserSessionData); - - public getIdToken(): CognitoIdToken; - public getRefreshToken(): CognitoRefreshToken; - public getAccessToken(): CognitoAccessToken; - public isValid(): boolean; - } - /* +declare module 'amazon-cognito-identity-js' { + //import * as AWS from "aws-sdk"; + + export type NodeCallback = (err?: E, result?: T) => void; + + export interface CodeDeliveryDetails { + AttributeName: string; + DeliveryMedium: string; + Destination: string; + } + + export interface IAuthenticationCallback { + onSuccess: ( + session: CognitoUserSession, + userConfirmationNecessary?: boolean + ) => void; + onFailure: (err: any) => void; + newPasswordRequired?: ( + userAttributes: any, + requiredAttributes: any + ) => void; + mfaRequired?: (challengeName: any, challengeParameters: any) => void; + totpRequired?: (challengeName: any, challengeParameters: any) => void; + customChallenge?: (challengeParameters: any) => void; + mfaSetup?: (challengeName: any, challengeParameters: any) => void; + selectMFAType?: (challengeName: any, challengeParameters: any) => void; + } + + export interface IMfaSettings { + PreferredMfa: boolean; + Enabled: boolean; + } + export interface IAuthenticationDetailsData { + Username: string; + Password?: string; + ValidationData?: { [key: string]: any }; + } + + export class AuthenticationDetails { + constructor(data: IAuthenticationDetailsData); + + public getUsername(): string; + public getPassword(): string; + public getValidationData(): any[]; + } + + export interface ICognitoStorage { + setItem(key: string, value: string): void; + getItem(key: string): string; + removeItem(key: string): void; + clear(): void; + } + + export interface ICognitoUserData { + Username: string; + Pool: CognitoUserPool; + Storage?: ICognitoStorage; + } + + export class CognitoUser { + constructor(data: ICognitoUserData); + + public setSignInUserSession( + signInUserSession: CognitoUserSession + ): void; + public getSignInUserSession(): CognitoUserSession | null; + public getUsername(): string; + + public getAuthenticationFlowType(): string; + public setAuthenticationFlowType( + authenticationFlowType: string + ): string; + + public getSession(callback: Function): any; + public refreshSession( + refreshToken: CognitoRefreshToken, + callback: NodeCallback + ): void; + public authenticateUser( + authenticationDetails: AuthenticationDetails, + callbacks: IAuthenticationCallback + ): void; + public initiateAuth( + authenticationDetails: AuthenticationDetails, + callbacks: IAuthenticationCallback + ): void; + public confirmRegistration( + code: string, + forceAliasCreation: boolean, + callback: NodeCallback + ): void; + public sendCustomChallengeAnswer( + answerChallenge: any, + callback: IAuthenticationCallback + ): void; + public resendConfirmationCode( + callback: NodeCallback + ): void; + public changePassword( + oldPassword: string, + newPassword: string, + callback: NodeCallback + ): void; + public forgotPassword(callbacks: { + onSuccess: (data: any) => void; + onFailure: (err: Error) => void; + inputVerificationCode?: (data: any) => void; + }): void; + public confirmPassword( + verificationCode: string, + newPassword: string, + callbacks: { + onSuccess: () => void; + onFailure: (err: Error) => void; + } + ): void; + public setDeviceStatusRemembered(callbacks: { + onSuccess: (success: string) => void; + onFailure: (err: any) => void; + }): void; + public setDeviceStatusNotRemembered(callbacks: { + onSuccess: (success: string) => void; + onFailure: (err: any) => void; + }): void; + public getDevice(callbacks: { + onSuccess: (success: string) => void; + onFailure: (err: Error) => void; + }): any; + public forgetDevice(callbacks: { + onSuccess: (success: string) => void; + onFailure: (err: Error) => void; + }): void; + public forgetSpecificDevice( + deviceKey: string, + callbacks: { + onSuccess: (success: string) => void; + onFailure: (err: Error) => void; + } + ): void; + public sendMFACode( + confirmationCode: string, + callbacks: { + onSuccess: (session: CognitoUserSession) => void; + onFailure: (err: any) => void; + }, + mfaType?: string + ): void; + public listDevices( + limit: number, + paginationToken: string, + callbacks: { + onSuccess: (data: any) => void; + onFailure: (err: Error) => void; + } + ): void; + public completeNewPasswordChallenge( + newPassword: string, + requiredAttributeData: any, + callbacks: { + onSuccess: (session: CognitoUserSession) => void; + onFailure: (err: any) => void; + mfaRequired?: ( + challengeName: any, + challengeParameters: any + ) => void; + customChallenge?: (challengeParameters: any) => void; + mfaSetup?: ( + challengeName: any, + challengeParameters: any + ) => void; + } + ): void; + public signOut(): void; + public globalSignOut(callbacks: { + onSuccess: (msg: string) => void; + onFailure: (err: Error) => void; + }): void; + public verifyAttribute( + attributeName: string, + confirmationCode: string, + callbacks: { + onSuccess: (success: string) => void; + onFailure: (err: Error) => void; + } + ): void; + public getUserAttributes( + callback: NodeCallback + ): void; + public updateAttributes( + attributes: ICognitoUserAttributeData[], + callback: NodeCallback + ): void; + public deleteAttributes( + attributeList: string[], + callback: NodeCallback + ): void; + public getAttributeVerificationCode( + name: string, + callback: { + onSuccess: () => void; + onFailure: (err: Error) => void; + inputVerificationCode?: (data: string) => void | null; + } + ): void; + public deleteUser(callback: NodeCallback): void; + public enableMFA(callback: NodeCallback): void; + public disableMFA(callback: NodeCallback): void; + public getMFAOptions(callback: NodeCallback): void; + public getUserData(callback: NodeCallback): void; + public associateSoftwareToken(callbacks: { + associateSecretCode: (secretCode: string) => void; + onFailure: (err: any) => void; + }): void; + public verifySoftwareToken( + totpCode: string, + friendlyDeviceName: string, + callbacks: { + onSuccess: (session: CognitoUserSession) => void; + onFailure: (err: Error) => void; + } + ): void; + public setUserMfaPreference( + smsMfaSettings: IMfaSettings | null, + softwareTokenMfaSettings: IMfaSettings | null, + callback: NodeCallback + ): void; + public sendMFASelectionAnswer( + answerChallenge: string, + callbacks: { + onSuccess: (session: CognitoUserSession) => void; + onFailure: (err: any) => void; + mfaRequired?: ( + challengeName: any, + challengeParameters: any + ) => void; + totpRequired?: ( + challengeName: any, + challengeParameters: any + ) => void; + } + ): void; + } + + export interface MFAOption { + DeliveryMedium: 'SMS' | 'EMAIL'; + AttributeName: string; + } + + export interface UserData { + MFAOptions: MFAOption[]; + PreferredMfaSetting: string; + UserAttributes: ICognitoUserAttributeData[]; + UserMFASettingList: string[]; + Username: string; + } + + export interface ICognitoUserAttributeData { + Name: string; + Value: string; + } + + export class CognitoUserAttribute { + constructor(data: ICognitoUserAttributeData); + + public getValue(): string; + public setValue(value: string): CognitoUserAttribute; + public getName(): string; + public setName(name: string): CognitoUserAttribute; + public toString(): string; + public toJSON(): Object; + } + + export interface ISignUpResult { + user: CognitoUser; + userConfirmed: boolean; + userSub: string; + codeDeliveryDetails: CodeDeliveryDetails; + } + + export interface ICognitoUserPoolData { + UserPoolId: string; + ClientId: string; + endpoint?: string; + Storage?: ICognitoStorage; + } + + export class CognitoUserPool { + constructor(data: ICognitoUserPoolData); + + public getUserPoolId(): string; + public getClientId(): string; + + public signUp( + username: string, + password: string, + userAttributes: CognitoUserAttribute[], + validationData: CognitoUserAttribute[], + callback: NodeCallback + ): void; + + public getCurrentUser(): CognitoUser | null; + } + + export interface ICognitoUserSessionData { + IdToken: CognitoIdToken; + AccessToken: CognitoAccessToken; + RefreshToken?: CognitoRefreshToken; + } + + export class CognitoUserSession { + constructor(data: ICognitoUserSessionData); + + public getIdToken(): CognitoIdToken; + public getRefreshToken(): CognitoRefreshToken; + public getAccessToken(): CognitoAccessToken; + public isValid(): boolean; + } + /* export class CognitoIdentityServiceProvider { public config: AWS.CognitoIdentityServiceProvider.Types.ClientConfiguration; } */ - export class CognitoAccessToken { - payload: {[key: string]: any}; - - constructor({ AccessToken }: { AccessToken: string }); - - public getJwtToken(): string; - public getExpiration(): number; - public getIssuedAt(): number; - public decodePayload(): { [id: string]: any; } - } - - export class CognitoIdToken { - payload: {[key: string]: any}; - - constructor({ IdToken }: { IdToken: string }); - - public getJwtToken(): string; - public getExpiration(): number; - public getIssuedAt(): number; - public decodePayload(): { [id: string]: any; } - } - - export class CognitoRefreshToken { - constructor({ RefreshToken }: { RefreshToken: string }); - - public getToken(): string; - } - - export interface ICookieStorageData { - domain: string; - path?: string; - expires?: number; - secure?: boolean; - } - export class CookieStorage implements ICognitoStorage { - constructor(data: ICookieStorageData); - setItem(key: string, value: string): void; - getItem(key: string): string; - removeItem(key: string): void; - clear(): void; - } + export class CognitoAccessToken { + payload: { [key: string]: any }; + + constructor({ AccessToken }: { AccessToken: string }); + + public getJwtToken(): string; + public getExpiration(): number; + public getIssuedAt(): number; + public decodePayload(): { [id: string]: any }; + } + + export class CognitoIdToken { + payload: { [key: string]: any }; + + constructor({ IdToken }: { IdToken: string }); + + public getJwtToken(): string; + public getExpiration(): number; + public getIssuedAt(): number; + public decodePayload(): { [id: string]: any }; + } + + export class CognitoRefreshToken { + constructor({ RefreshToken }: { RefreshToken: string }); + + public getToken(): string; + } + + export interface ICookieStorageData { + domain: string; + path?: string; + expires?: number; + secure?: boolean; + } + export class CookieStorage implements ICognitoStorage { + constructor(data: ICookieStorageData); + setItem(key: string, value: string): void; + getItem(key: string): string; + removeItem(key: string): void; + clear(): void; + } } diff --git a/packages/amazon-cognito-identity-js/src/AuthenticationDetails.js b/packages/amazon-cognito-identity-js/src/AuthenticationDetails.js index 4420484d591..571513e43ce 100644 --- a/packages/amazon-cognito-identity-js/src/AuthenticationDetails.js +++ b/packages/amazon-cognito-identity-js/src/AuthenticationDetails.js @@ -17,47 +17,47 @@ /** @class */ export default class AuthenticationDetails { - /** - * Constructs a new AuthenticationDetails object - * @param {object=} data Creation options. - * @param {string} data.Username User being authenticated. - * @param {string} data.Password Plain-text password to authenticate with. - * @param {(AttributeArg[])?} data.ValidationData Application extra metadata. - * @param {(AttributeArg[])?} data.AuthParamaters Authentication paramaters for custom auth. - */ - constructor(data) { - const { ValidationData, Username, Password, AuthParameters } = data || {}; - this.validationData = ValidationData || {}; - this.authParameters = AuthParameters || {}; - this.username = Username; - this.password = Password; - } + /** + * Constructs a new AuthenticationDetails object + * @param {object=} data Creation options. + * @param {string} data.Username User being authenticated. + * @param {string} data.Password Plain-text password to authenticate with. + * @param {(AttributeArg[])?} data.ValidationData Application extra metadata. + * @param {(AttributeArg[])?} data.AuthParamaters Authentication paramaters for custom auth. + */ + constructor(data) { + const { ValidationData, Username, Password, AuthParameters } = data || {}; + this.validationData = ValidationData || {}; + this.authParameters = AuthParameters || {}; + this.username = Username; + this.password = Password; + } - /** - * @returns {string} the record's username - */ - getUsername() { - return this.username; - } + /** + * @returns {string} the record's username + */ + getUsername() { + return this.username; + } - /** - * @returns {string} the record's password - */ - getPassword() { - return this.password; - } + /** + * @returns {string} the record's password + */ + getPassword() { + return this.password; + } - /** - * @returns {Array} the record's validationData - */ - getValidationData() { - return this.validationData; - } + /** + * @returns {Array} the record's validationData + */ + getValidationData() { + return this.validationData; + } - /** - * @returns {Array} the record's authParameters - */ - getAuthParameters() { - return this.authParameters; - } + /** + * @returns {Array} the record's authParameters + */ + getAuthParameters() { + return this.authParameters; + } } diff --git a/packages/amazon-cognito-identity-js/src/AuthenticationHelper.js b/packages/amazon-cognito-identity-js/src/AuthenticationHelper.js index c909875bc18..15fd9d6c501 100644 --- a/packages/amazon-cognito-identity-js/src/AuthenticationHelper.js +++ b/packages/amazon-cognito-identity-js/src/AuthenticationHelper.js @@ -21,315 +21,332 @@ import 'crypto-js/lib-typedarrays'; // necessary for crypto js import SHA256 from 'crypto-js/sha256'; import HmacSHA256 from 'crypto-js/hmac-sha256'; - const randomBytes = function(nBytes) { - return Buffer.from((CryptoJS.lib.WordArray.random(nBytes)).toString(), 'hex'); -} + return Buffer.from(CryptoJS.lib.WordArray.random(nBytes).toString(), 'hex'); +}; import BigInteger from './BigInteger'; -const initN = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1' - + '29024E088A67CC74020BBEA63B139B22514A08798E3404DD' - + 'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245' - + 'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' - + 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D' - + 'C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F' - + '83655D23DCA3AD961C62F356208552BB9ED529077096966D' - + '670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' - + 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9' - + 'DE2BCBF6955817183995497CEA956AE515D2261898FA0510' - + '15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64' - + 'ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' - + 'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B' - + 'F12FFA06D98A0864D87602733EC86A64521F2B18177B200C' - + 'BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31' - + '43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF'; +const initN = + 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1' + + '29024E088A67CC74020BBEA63B139B22514A08798E3404DD' + + 'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245' + + 'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' + + 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D' + + 'C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F' + + '83655D23DCA3AD961C62F356208552BB9ED529077096966D' + + '670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' + + 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9' + + 'DE2BCBF6955817183995497CEA956AE515D2261898FA0510' + + '15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64' + + 'ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' + + 'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B' + + 'F12FFA06D98A0864D87602733EC86A64521F2B18177B200C' + + 'BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31' + + '43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF'; const newPasswordRequiredChallengeUserAttributePrefix = 'userAttributes.'; /** @class */ export default class AuthenticationHelper { - /** - * Constructs a new AuthenticationHelper object - * @param {string} PoolName Cognito user pool name. - */ - constructor(PoolName) { - this.N = new BigInteger(initN, 16); - this.g = new BigInteger('2', 16); - this.k = new BigInteger(this.hexHash(`00${this.N.toString(16)}0${this.g.toString(16)}`), 16); - - this.smallAValue = this.generateRandomSmallA(); - this.getLargeAValue(() => {}); - - this.infoBits = Buffer.from('Caldera Derived Key', 'utf8'); - - this.poolName = PoolName; - } - - /** - * @returns {BigInteger} small A, a random number - */ - getSmallAValue() { - return this.smallAValue; - } - - /** - * @param {nodeCallback} callback Called with (err, largeAValue) - * @returns {void} - */ - getLargeAValue(callback) { - if (this.largeAValue) { - callback(null, this.largeAValue); - } else { - this.calculateA(this.smallAValue, (err, largeAValue) => { - if (err) { - callback(err, null); - } - - this.largeAValue = largeAValue; - callback(null, this.largeAValue); - }); - } - } - - /** - * helper function to generate a random big integer - * @returns {BigInteger} a random value. - * @private - */ - generateRandomSmallA() { - const hexRandom = randomBytes(128).toString('hex'); - - const randomBigInt = new BigInteger(hexRandom, 16); - const smallABigInt = randomBigInt.mod(this.N); - - return smallABigInt; - } - - /** - * helper function to generate a random string - * @returns {string} a random value. - * @private - */ - generateRandomString() { - return randomBytes(40).toString('base64'); - } - - /** - * @returns {string} Generated random value included in password hash. - */ - getRandomPassword() { - return this.randomPassword; - } - - /** - * @returns {string} Generated random value included in devices hash. - */ - getSaltDevices() { - return this.SaltToHashDevices; - } - - /** - * @returns {string} Value used to verify devices. - */ - getVerifierDevices() { - return this.verifierDevices; - } - - /** - * Generate salts and compute verifier. - * @param {string} deviceGroupKey Devices to generate verifier for. - * @param {string} username User to generate verifier for. - * @param {nodeCallback} callback Called with (err, null) - * @returns {void} - */ - generateHashDevice(deviceGroupKey, username, callback) { - this.randomPassword = this.generateRandomString(); - const combinedString = `${deviceGroupKey}${username}:${this.randomPassword}`; - const hashedString = this.hash(combinedString); - - const hexRandom = randomBytes(16).toString('hex'); - this.SaltToHashDevices = this.padHex(new BigInteger(hexRandom, 16)); - - this.g.modPow( - new BigInteger(this.hexHash(this.SaltToHashDevices + hashedString), 16), - this.N, - (err, verifierDevicesNotPadded) => { - if (err) { - callback(err, null); - } - - this.verifierDevices = this.padHex(verifierDevicesNotPadded); - callback(null, null); - }); - } - - /** - * Calculate the client's public value A = g^a%N - * with the generated random number a - * @param {BigInteger} a Randomly generated small A. - * @param {nodeCallback} callback Called with (err, largeAValue) - * @returns {void} - * @private - */ - calculateA(a, callback) { - this.g.modPow(a, this.N, (err, A) => { - if (err) { - callback(err, null); - } - - if (A.mod(this.N).equals(BigInteger.ZERO)) { - callback(new Error('Illegal paramater. A mod N cannot be 0.'), null); - } - - callback(null, A); - }); - } - - /** - * Calculate the client's value U which is the hash of A and B - * @param {BigInteger} A Large A value. - * @param {BigInteger} B Server B value. - * @returns {BigInteger} Computed U value. - * @private - */ - calculateU(A, B) { - this.UHexHash = this.hexHash(this.padHex(A) + this.padHex(B)); - const finalU = new BigInteger(this.UHexHash, 16); - - return finalU; - } - - /** - * Calculate a hash from a bitArray - * @param {Buffer} buf Value to hash. - * @returns {String} Hex-encoded hash. - * @private - */ - hash(buf) { - const str = buf instanceof Buffer ? CryptoJS.lib.WordArray.create(buf) : buf; - const hashHex = SHA256(str).toString(); - - return (new Array(64 - hashHex.length).join('0')) + hashHex; - } - - /** - * Calculate a hash from a hex string - * @param {String} hexStr Value to hash. - * @returns {String} Hex-encoded hash. - * @private - */ - hexHash(hexStr) { - return this.hash(Buffer.from(hexStr, 'hex')); - } - - /** - * Standard hkdf algorithm - * @param {Buffer} ikm Input key material. - * @param {Buffer} salt Salt value. - * @returns {Buffer} Strong key material. - * @private - */ - computehkdf(ikm, salt) { - const infoBitsWordArray = CryptoJS.lib.WordArray.create( - Buffer.concat([ - this.infoBits, - Buffer.from(String.fromCharCode(1), 'utf8'), - ]) - ); - const ikmWordArray = ikm instanceof Buffer ? CryptoJS.lib.WordArray.create(ikm) : ikm; - const saltWordArray = salt instanceof Buffer ? CryptoJS.lib.WordArray.create(salt) : salt; - - const prk = HmacSHA256(ikmWordArray, saltWordArray); - const hmac = HmacSHA256(infoBitsWordArray, prk); - return Buffer.from(hmac.toString(), 'hex').slice(0, 16); - } - - /** - * Calculates the final hkdf based on computed S value, and computed U value and the key - * @param {String} username Username. - * @param {String} password Password. - * @param {BigInteger} serverBValue Server B value. - * @param {BigInteger} salt Generated salt. - * @param {nodeCallback} callback Called with (err, hkdfValue) - * @returns {void} - */ - getPasswordAuthenticationKey(username, password, serverBValue, salt, callback) { - if (serverBValue.mod(this.N).equals(BigInteger.ZERO)) { - throw new Error('B cannot be zero.'); - } - - this.UValue = this.calculateU(this.largeAValue, serverBValue); - - if (this.UValue.equals(BigInteger.ZERO)) { - throw new Error('U cannot be zero.'); - } - - const usernamePassword = `${this.poolName}${username}:${password}`; - const usernamePasswordHash = this.hash(usernamePassword); - - const xValue = new BigInteger(this.hexHash(this.padHex(salt) + usernamePasswordHash), 16); - this.calculateS(xValue, serverBValue, (err, sValue) => { - if (err) { - callback(err, null); - } - - const hkdf = this.computehkdf( - Buffer.from(this.padHex(sValue), 'hex'), - Buffer.from(this.padHex(this.UValue.toString(16)), 'hex')); - - callback(null, hkdf); - }); - } - - /** - * Calculates the S value used in getPasswordAuthenticationKey - * @param {BigInteger} xValue Salted password hash value. - * @param {BigInteger} serverBValue Server B value. - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - calculateS(xValue, serverBValue, callback) { - this.g.modPow(xValue, this.N, (err, gModPowXN) => { - if (err) { - callback(err, null); - } - - const intValue2 = serverBValue.subtract(this.k.multiply(gModPowXN)); - intValue2.modPow( - this.smallAValue.add(this.UValue.multiply(xValue)), - this.N, - (err2, result) => { - if (err2) { - callback(err2, null); - } - - callback(null, result.mod(this.N)); - } - ); - }); - } - - /** - * Return constant newPasswordRequiredChallengeUserAttributePrefix - * @return {newPasswordRequiredChallengeUserAttributePrefix} constant prefix value - */ - getNewPasswordRequiredChallengeUserAttributePrefix() { - return newPasswordRequiredChallengeUserAttributePrefix; - } - - /** - * Converts a BigInteger (or hex string) to hex format padded with zeroes for hashing - * @param {BigInteger|String} bigInt Number or string to pad. - * @returns {String} Padded hex string. - */ - padHex(bigInt) { - let hashStr = bigInt.toString(16); - if (hashStr.length % 2 === 1) { - hashStr = `0${hashStr}`; - } else if ('89ABCDEFabcdef'.indexOf(hashStr[0]) !== -1) { - hashStr = `00${hashStr}`; - } - return hashStr; - } + /** + * Constructs a new AuthenticationHelper object + * @param {string} PoolName Cognito user pool name. + */ + constructor(PoolName) { + this.N = new BigInteger(initN, 16); + this.g = new BigInteger('2', 16); + this.k = new BigInteger( + this.hexHash(`00${this.N.toString(16)}0${this.g.toString(16)}`), + 16 + ); + + this.smallAValue = this.generateRandomSmallA(); + this.getLargeAValue(() => {}); + + this.infoBits = Buffer.from('Caldera Derived Key', 'utf8'); + + this.poolName = PoolName; + } + + /** + * @returns {BigInteger} small A, a random number + */ + getSmallAValue() { + return this.smallAValue; + } + + /** + * @param {nodeCallback} callback Called with (err, largeAValue) + * @returns {void} + */ + getLargeAValue(callback) { + if (this.largeAValue) { + callback(null, this.largeAValue); + } else { + this.calculateA(this.smallAValue, (err, largeAValue) => { + if (err) { + callback(err, null); + } + + this.largeAValue = largeAValue; + callback(null, this.largeAValue); + }); + } + } + + /** + * helper function to generate a random big integer + * @returns {BigInteger} a random value. + * @private + */ + generateRandomSmallA() { + const hexRandom = randomBytes(128).toString('hex'); + + const randomBigInt = new BigInteger(hexRandom, 16); + const smallABigInt = randomBigInt.mod(this.N); + + return smallABigInt; + } + + /** + * helper function to generate a random string + * @returns {string} a random value. + * @private + */ + generateRandomString() { + return randomBytes(40).toString('base64'); + } + + /** + * @returns {string} Generated random value included in password hash. + */ + getRandomPassword() { + return this.randomPassword; + } + + /** + * @returns {string} Generated random value included in devices hash. + */ + getSaltDevices() { + return this.SaltToHashDevices; + } + + /** + * @returns {string} Value used to verify devices. + */ + getVerifierDevices() { + return this.verifierDevices; + } + + /** + * Generate salts and compute verifier. + * @param {string} deviceGroupKey Devices to generate verifier for. + * @param {string} username User to generate verifier for. + * @param {nodeCallback} callback Called with (err, null) + * @returns {void} + */ + generateHashDevice(deviceGroupKey, username, callback) { + this.randomPassword = this.generateRandomString(); + const combinedString = `${deviceGroupKey}${username}:${this.randomPassword}`; + const hashedString = this.hash(combinedString); + + const hexRandom = randomBytes(16).toString('hex'); + this.SaltToHashDevices = this.padHex(new BigInteger(hexRandom, 16)); + + this.g.modPow( + new BigInteger(this.hexHash(this.SaltToHashDevices + hashedString), 16), + this.N, + (err, verifierDevicesNotPadded) => { + if (err) { + callback(err, null); + } + + this.verifierDevices = this.padHex(verifierDevicesNotPadded); + callback(null, null); + } + ); + } + + /** + * Calculate the client's public value A = g^a%N + * with the generated random number a + * @param {BigInteger} a Randomly generated small A. + * @param {nodeCallback} callback Called with (err, largeAValue) + * @returns {void} + * @private + */ + calculateA(a, callback) { + this.g.modPow(a, this.N, (err, A) => { + if (err) { + callback(err, null); + } + + if (A.mod(this.N).equals(BigInteger.ZERO)) { + callback(new Error('Illegal paramater. A mod N cannot be 0.'), null); + } + + callback(null, A); + }); + } + + /** + * Calculate the client's value U which is the hash of A and B + * @param {BigInteger} A Large A value. + * @param {BigInteger} B Server B value. + * @returns {BigInteger} Computed U value. + * @private + */ + calculateU(A, B) { + this.UHexHash = this.hexHash(this.padHex(A) + this.padHex(B)); + const finalU = new BigInteger(this.UHexHash, 16); + + return finalU; + } + + /** + * Calculate a hash from a bitArray + * @param {Buffer} buf Value to hash. + * @returns {String} Hex-encoded hash. + * @private + */ + hash(buf) { + const str = + buf instanceof Buffer ? CryptoJS.lib.WordArray.create(buf) : buf; + const hashHex = SHA256(str).toString(); + + return new Array(64 - hashHex.length).join('0') + hashHex; + } + + /** + * Calculate a hash from a hex string + * @param {String} hexStr Value to hash. + * @returns {String} Hex-encoded hash. + * @private + */ + hexHash(hexStr) { + return this.hash(Buffer.from(hexStr, 'hex')); + } + + /** + * Standard hkdf algorithm + * @param {Buffer} ikm Input key material. + * @param {Buffer} salt Salt value. + * @returns {Buffer} Strong key material. + * @private + */ + computehkdf(ikm, salt) { + const infoBitsWordArray = CryptoJS.lib.WordArray.create( + Buffer.concat([ + this.infoBits, + Buffer.from(String.fromCharCode(1), 'utf8'), + ]) + ); + const ikmWordArray = + ikm instanceof Buffer ? CryptoJS.lib.WordArray.create(ikm) : ikm; + const saltWordArray = + salt instanceof Buffer ? CryptoJS.lib.WordArray.create(salt) : salt; + + const prk = HmacSHA256(ikmWordArray, saltWordArray); + const hmac = HmacSHA256(infoBitsWordArray, prk); + return Buffer.from(hmac.toString(), 'hex').slice(0, 16); + } + + /** + * Calculates the final hkdf based on computed S value, and computed U value and the key + * @param {String} username Username. + * @param {String} password Password. + * @param {BigInteger} serverBValue Server B value. + * @param {BigInteger} salt Generated salt. + * @param {nodeCallback} callback Called with (err, hkdfValue) + * @returns {void} + */ + getPasswordAuthenticationKey( + username, + password, + serverBValue, + salt, + callback + ) { + if (serverBValue.mod(this.N).equals(BigInteger.ZERO)) { + throw new Error('B cannot be zero.'); + } + + this.UValue = this.calculateU(this.largeAValue, serverBValue); + + if (this.UValue.equals(BigInteger.ZERO)) { + throw new Error('U cannot be zero.'); + } + + const usernamePassword = `${this.poolName}${username}:${password}`; + const usernamePasswordHash = this.hash(usernamePassword); + + const xValue = new BigInteger( + this.hexHash(this.padHex(salt) + usernamePasswordHash), + 16 + ); + this.calculateS(xValue, serverBValue, (err, sValue) => { + if (err) { + callback(err, null); + } + + const hkdf = this.computehkdf( + Buffer.from(this.padHex(sValue), 'hex'), + Buffer.from(this.padHex(this.UValue.toString(16)), 'hex') + ); + + callback(null, hkdf); + }); + } + + /** + * Calculates the S value used in getPasswordAuthenticationKey + * @param {BigInteger} xValue Salted password hash value. + * @param {BigInteger} serverBValue Server B value. + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + calculateS(xValue, serverBValue, callback) { + this.g.modPow(xValue, this.N, (err, gModPowXN) => { + if (err) { + callback(err, null); + } + + const intValue2 = serverBValue.subtract(this.k.multiply(gModPowXN)); + intValue2.modPow( + this.smallAValue.add(this.UValue.multiply(xValue)), + this.N, + (err2, result) => { + if (err2) { + callback(err2, null); + } + + callback(null, result.mod(this.N)); + } + ); + }); + } + + /** + * Return constant newPasswordRequiredChallengeUserAttributePrefix + * @return {newPasswordRequiredChallengeUserAttributePrefix} constant prefix value + */ + getNewPasswordRequiredChallengeUserAttributePrefix() { + return newPasswordRequiredChallengeUserAttributePrefix; + } + + /** + * Converts a BigInteger (or hex string) to hex format padded with zeroes for hashing + * @param {BigInteger|String} bigInt Number or string to pad. + * @returns {String} Padded hex string. + */ + padHex(bigInt) { + let hashStr = bigInt.toString(16); + if (hashStr.length % 2 === 1) { + hashStr = `0${hashStr}`; + } else if ('89ABCDEFabcdef'.indexOf(hashStr[0]) !== -1) { + hashStr = `00${hashStr}`; + } + return hashStr; + } } diff --git a/packages/amazon-cognito-identity-js/src/BigInteger.js b/packages/amazon-cognito-identity-js/src/BigInteger.js index 1d9e7f87519..25d3c1600e2 100644 --- a/packages/amazon-cognito-identity-js/src/BigInteger.js +++ b/packages/amazon-cognito-identity-js/src/BigInteger.js @@ -50,12 +50,12 @@ export default BigInteger; // (public) Constructor function BigInteger(a, b) { - if (a != null) this.fromString(a, b); + if (a != null) this.fromString(a, b); } // return new, unset BigInteger function nbi() { - return new BigInteger(null); + return new BigInteger(null); } // Bits per digit @@ -63,7 +63,7 @@ var dbits; // JavaScript engine analysis var canary = 0xdeadbeefcafe; -var j_lm = ((canary&0xffffff)==0xefcafe); +var j_lm = (canary & 0xffffff) == 0xefcafe; // am: Compute w_j += (x*this_i), propagate carries, // c is initial carry, returns final carry. @@ -73,55 +73,56 @@ var j_lm = ((canary&0xffffff)==0xefcafe); // am1: use a single mult and divide to get the high bits, // max digit bits should be 26 because // max internal value = 2*dvalue^2-2*dvalue (< 2^53) -function am1(i,x,w,j,c,n) { - while(--n >= 0) { - var v = x*this[i++]+w[j]+c; - c = Math.floor(v/0x4000000); - w[j++] = v&0x3ffffff; - } - return c; +function am1(i, x, w, j, c, n) { + while (--n >= 0) { + var v = x * this[i++] + w[j] + c; + c = Math.floor(v / 0x4000000); + w[j++] = v & 0x3ffffff; + } + return c; } // am2 avoids a big mult-and-extract completely. // Max digit bits should be <= 30 because we do bitwise ops // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) -function am2(i,x,w,j,c,n) { - var xl = x&0x7fff, xh = x>>15; - while(--n >= 0) { - var l = this[i]&0x7fff; - var h = this[i++]>>15; - var m = xh*l+h*xl; - l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff); - c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); - w[j++] = l&0x3fffffff; - } - return c; +function am2(i, x, w, j, c, n) { + var xl = x & 0x7fff, + xh = x >> 15; + while (--n >= 0) { + var l = this[i] & 0x7fff; + var h = this[i++] >> 15; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff); + c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30); + w[j++] = l & 0x3fffffff; + } + return c; } // Alternately, set max digit bits to 28 since some // browsers slow down when dealing with 32-bit numbers. -function am3(i,x,w,j,c,n) { - var xl = x&0x3fff, xh = x>>14; - while(--n >= 0) { - var l = this[i]&0x3fff; - var h = this[i++]>>14; - var m = xh*l+h*xl; - l = xl*l+((m&0x3fff)<<14)+w[j]+c; - c = (l>>28)+(m>>14)+xh*h; - w[j++] = l&0xfffffff; - } - return c; -} -var inBrowser = typeof navigator !== "undefined"; -if(inBrowser && j_lm && (navigator.appName == "Microsoft Internet Explorer")) { - BigInteger.prototype.am = am2; - dbits = 30; -} -else if(inBrowser && j_lm && (navigator.appName != "Netscape")) { - BigInteger.prototype.am = am1; - dbits = 26; -} -else { // Mozilla/Netscape seems to prefer am3 - BigInteger.prototype.am = am3; - dbits = 28; +function am3(i, x, w, j, c, n) { + var xl = x & 0x3fff, + xh = x >> 14; + while (--n >= 0) { + var l = this[i] & 0x3fff; + var h = this[i++] >> 14; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x3fff) << 14) + w[j] + c; + c = (l >> 28) + (m >> 14) + xh * h; + w[j++] = l & 0xfffffff; + } + return c; +} +var inBrowser = typeof navigator !== 'undefined'; +if (inBrowser && j_lm && navigator.appName == 'Microsoft Internet Explorer') { + BigInteger.prototype.am = am2; + dbits = 30; +} else if (inBrowser && j_lm && navigator.appName != 'Netscape') { + BigInteger.prototype.am = am1; + dbits = 26; +} else { + // Mozilla/Netscape seems to prefer am3 + BigInteger.prototype.am = am3; + dbits = 28; } BigInteger.prototype.DB = dbits; @@ -134,377 +135,380 @@ BigInteger.prototype.F1 = BI_FP - dbits; BigInteger.prototype.F2 = 2 * dbits - BI_FP; // Digit conversions -var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; +var BI_RM = '0123456789abcdefghijklmnopqrstuvwxyz'; var BI_RC = new Array(); var rr, vv; -rr = "0".charCodeAt(0); -for (vv = 0; vv <= 9; ++vv) - BI_RC[rr++] = vv; -rr = "a".charCodeAt(0); -for (vv = 10; vv < 36; ++vv) - BI_RC[rr++] = vv; -rr = "A".charCodeAt(0); -for (vv = 10; vv < 36; ++vv) - BI_RC[rr++] = vv; +rr = '0'.charCodeAt(0); +for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv; +rr = 'a'.charCodeAt(0); +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; +rr = 'A'.charCodeAt(0); +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; function int2char(n) { - return BI_RM.charAt(n); + return BI_RM.charAt(n); } function intAt(s, i) { - var c = BI_RC[s.charCodeAt(i)]; - return c == null ? -1 : c; + var c = BI_RC[s.charCodeAt(i)]; + return c == null ? -1 : c; } // (protected) copy this to r function bnpCopyTo(r) { - for (var i = this.t - 1; i >= 0; --i) - r[i] = this[i]; - r.t = this.t; - r.s = this.s; + for (var i = this.t - 1; i >= 0; --i) r[i] = this[i]; + r.t = this.t; + r.s = this.s; } // (protected) set from integer value x, -DV <= x < DV function bnpFromInt(x) { - this.t = 1; - this.s = x < 0 ? -1 : 0; - if (x > 0) this[0] = x; - else if (x < -1) this[0] = x + this.DV; - else this.t = 0; + this.t = 1; + this.s = x < 0 ? -1 : 0; + if (x > 0) this[0] = x; + else if (x < -1) this[0] = x + this.DV; + else this.t = 0; } // return bigint initialized to value function nbv(i) { - var r = nbi(); + var r = nbi(); - r.fromInt(i); + r.fromInt(i); - return r; + return r; } // (protected) set from string and radix function bnpFromString(s, b) { - var k; - if (b == 16) k = 4; - else if (b == 8) k = 3; - else if (b == 2) k = 1; - else if (b == 32) k = 5; - else if (b == 4) k = 2; - else throw new Error("Only radix 2, 4, 8, 16, 32 are supported"); - this.t = 0; - this.s = 0; - var i = s.length, mi = false, sh = 0; - while (--i >= 0) { - var x = intAt(s, i); - if (x < 0) { - if (s.charAt(i) == "-") mi = true; - continue; - } - mi = false; - if (sh == 0) this[this.t++] = x; - else if (sh + k > this.DB) { - this[this.t - 1] |= (x & (1 << this.DB - sh) - 1) << sh; - this[this.t++] = x >> this.DB - sh; - } else this[this.t - 1] |= x << sh; - sh += k; - if (sh >= this.DB) sh -= this.DB; - } - this.clamp(); - if (mi) BigInteger.ZERO.subTo(this, this); + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else throw new Error('Only radix 2, 4, 8, 16, 32 are supported'); + this.t = 0; + this.s = 0; + var i = s.length, + mi = false, + sh = 0; + while (--i >= 0) { + var x = intAt(s, i); + if (x < 0) { + if (s.charAt(i) == '-') mi = true; + continue; + } + mi = false; + if (sh == 0) this[this.t++] = x; + else if (sh + k > this.DB) { + this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh; + this[this.t++] = x >> (this.DB - sh); + } else this[this.t - 1] |= x << sh; + sh += k; + if (sh >= this.DB) sh -= this.DB; + } + this.clamp(); + if (mi) BigInteger.ZERO.subTo(this, this); } // (protected) clamp off excess high words function bnpClamp() { - var c = this.s & this.DM; - while (this.t > 0 && this[this.t - 1] == c) - --this.t; + var c = this.s & this.DM; + while (this.t > 0 && this[this.t - 1] == c) --this.t; } // (public) return string representation in given radix function bnToString(b) { - if (this.s < 0) return "-" + this.negate().toString(); - var k; - if (b == 16) k = 4; - else if (b == 8) k = 3; - else if (b == 2) k = 1; - else if (b == 32) k = 5; - else if (b == 4) k = 2; - else throw new Error("Only radix 2, 4, 8, 16, 32 are supported"); - var km = (1 << k) - 1, d, m = false, r = "", i = this.t; - var p = this.DB - i * this.DB % k; - if (i-- > 0) { - if (p < this.DB && (d = this[i] >> p) > 0) { - m = true; - r = int2char(d); - } - while (i >= 0) { - if (p < k) { - d = (this[i] & (1 << p) - 1) << k - p; - d |= this[--i] >> (p += this.DB - k); - } else { - d = this[i] >> (p -= k) & km; - if (p <= 0) { - p += this.DB; - --i; - } - } - if (d > 0) m = true; - if (m) r += int2char(d); - } - } - return m ? r : "0"; + if (this.s < 0) return '-' + this.negate().toString(); + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else throw new Error('Only radix 2, 4, 8, 16, 32 are supported'); + var km = (1 << k) - 1, + d, + m = false, + r = '', + i = this.t; + var p = this.DB - ((i * this.DB) % k); + if (i-- > 0) { + if (p < this.DB && (d = this[i] >> p) > 0) { + m = true; + r = int2char(d); + } + while (i >= 0) { + if (p < k) { + d = (this[i] & ((1 << p) - 1)) << (k - p); + d |= this[--i] >> (p += this.DB - k); + } else { + d = (this[i] >> (p -= k)) & km; + if (p <= 0) { + p += this.DB; + --i; + } + } + if (d > 0) m = true; + if (m) r += int2char(d); + } + } + return m ? r : '0'; } // (public) -this function bnNegate() { - var r = nbi(); + var r = nbi(); - BigInteger.ZERO.subTo(this, r); + BigInteger.ZERO.subTo(this, r); - return r; + return r; } // (public) |this| function bnAbs() { - return this.s < 0 ? this.negate() : this; + return this.s < 0 ? this.negate() : this; } // (public) return + if this > a, - if this < a, 0 if equal function bnCompareTo(a) { - var r = this.s - a.s; - if (r != 0) return r; - var i = this.t; - r = i - a.t; - if (r != 0) return this.s < 0 ? -r : r; - while (--i >= 0) - if ((r = this[i] - a[i]) != 0) return r; - return 0; + var r = this.s - a.s; + if (r != 0) return r; + var i = this.t; + r = i - a.t; + if (r != 0) return this.s < 0 ? -r : r; + while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r; + return 0; } // returns bit length of the integer x function nbits(x) { - var r = 1, t; - if ((t = x >>> 16) != 0) { - x = t; - r += 16; - } - if ((t = x >> 8) != 0) { - x = t; - r += 8; - } - if ((t = x >> 4) != 0) { - x = t; - r += 4; - } - if ((t = x >> 2) != 0) { - x = t; - r += 2; - } - if ((t = x >> 1) != 0) { - x = t; - r += 1; - } - return r; + var r = 1, + t; + if ((t = x >>> 16) != 0) { + x = t; + r += 16; + } + if ((t = x >> 8) != 0) { + x = t; + r += 8; + } + if ((t = x >> 4) != 0) { + x = t; + r += 4; + } + if ((t = x >> 2) != 0) { + x = t; + r += 2; + } + if ((t = x >> 1) != 0) { + x = t; + r += 1; + } + return r; } // (public) return the number of bits in "this" function bnBitLength() { - if (this.t <= 0) return 0; - return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ this.s & this.DM); + if (this.t <= 0) return 0; + return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM)); } // (protected) r = this << n*DB function bnpDLShiftTo(n, r) { - var i; - for (i = this.t - 1; i >= 0; --i) - r[i + n] = this[i]; - for (i = n - 1; i >= 0; --i) - r[i] = 0; - r.t = this.t + n; - r.s = this.s; + var i; + for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i]; + for (i = n - 1; i >= 0; --i) r[i] = 0; + r.t = this.t + n; + r.s = this.s; } // (protected) r = this >> n*DB function bnpDRShiftTo(n, r) { - for (var i = n; i < this.t; ++i) - r[i - n] = this[i]; - r.t = Math.max(this.t - n, 0); - r.s = this.s; + for (var i = n; i < this.t; ++i) r[i - n] = this[i]; + r.t = Math.max(this.t - n, 0); + r.s = this.s; } // (protected) r = this << n function bnpLShiftTo(n, r) { - var bs = n % this.DB; - var cbs = this.DB - bs; - var bm = (1 << cbs) - 1; - var ds = Math.floor(n / this.DB), c = this.s << bs & this.DM, i; - for (i = this.t - 1; i >= 0; --i) { - r[i + ds + 1] = this[i] >> cbs | c; - c = (this[i] & bm) << bs; - } - for (i = ds - 1; i >= 0; --i) - r[i] = 0; - r[ds] = c; - r.t = this.t + ds + 1; - r.s = this.s; - r.clamp(); + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << cbs) - 1; + var ds = Math.floor(n / this.DB), + c = (this.s << bs) & this.DM, + i; + for (i = this.t - 1; i >= 0; --i) { + r[i + ds + 1] = (this[i] >> cbs) | c; + c = (this[i] & bm) << bs; + } + for (i = ds - 1; i >= 0; --i) r[i] = 0; + r[ds] = c; + r.t = this.t + ds + 1; + r.s = this.s; + r.clamp(); } // (protected) r = this >> n function bnpRShiftTo(n, r) { - r.s = this.s; - var ds = Math.floor(n / this.DB); - if (ds >= this.t) { - r.t = 0; - return; - } - var bs = n % this.DB; - var cbs = this.DB - bs; - var bm = (1 << bs) - 1; - r[0] = this[ds] >> bs; - for (var i = ds + 1; i < this.t; ++i) { - r[i - ds - 1] |= (this[i] & bm) << cbs; - r[i - ds] = this[i] >> bs; - } - if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs; - r.t = this.t - ds; - r.clamp(); + r.s = this.s; + var ds = Math.floor(n / this.DB); + if (ds >= this.t) { + r.t = 0; + return; + } + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << bs) - 1; + r[0] = this[ds] >> bs; + for (var i = ds + 1; i < this.t; ++i) { + r[i - ds - 1] |= (this[i] & bm) << cbs; + r[i - ds] = this[i] >> bs; + } + if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs; + r.t = this.t - ds; + r.clamp(); } // (protected) r = this - a function bnpSubTo(a, r) { - var i = 0, c = 0, m = Math.min(a.t, this.t); - while (i < m) { - c += this[i] - a[i]; - r[i++] = c & this.DM; - c >>= this.DB; - } - if (a.t < this.t) { - c -= a.s; - while (i < this.t) { - c += this[i]; - r[i++] = c & this.DM; - c >>= this.DB; - } - c += this.s; - } else { - c += this.s; - while (i < a.t) { - c -= a[i]; - r[i++] = c & this.DM; - c >>= this.DB; - } - c -= a.s; - } - r.s = c < 0 ? -1 : 0; - if (c < -1) r[i++] = this.DV + c; - else if (c > 0) r[i++] = c; - r.t = i; - r.clamp(); + var i = 0, + c = 0, + m = Math.min(a.t, this.t); + while (i < m) { + c += this[i] - a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + if (a.t < this.t) { + c -= a.s; + while (i < this.t) { + c += this[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += this.s; + } else { + c += this.s; + while (i < a.t) { + c -= a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c -= a.s; + } + r.s = c < 0 ? -1 : 0; + if (c < -1) r[i++] = this.DV + c; + else if (c > 0) r[i++] = c; + r.t = i; + r.clamp(); } // (protected) r = this * a, r != this,a (HAC 14.12) // "this" should be the larger one if appropriate. function bnpMultiplyTo(a, r) { - var x = this.abs(), y = a.abs(); - var i = x.t; - r.t = i + y.t; - while (--i >= 0) - r[i] = 0; - for (i = 0; i < y.t; ++i) - r[i + x.t] = x.am(0, y[i], r, i, 0, x.t); - r.s = 0; - r.clamp(); - if (this.s != a.s) BigInteger.ZERO.subTo(r, r); + var x = this.abs(), + y = a.abs(); + var i = x.t; + r.t = i + y.t; + while (--i >= 0) r[i] = 0; + for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t); + r.s = 0; + r.clamp(); + if (this.s != a.s) BigInteger.ZERO.subTo(r, r); } // (protected) r = this^2, r != this (HAC 14.16) function bnpSquareTo(r) { - var x = this.abs(); - var i = r.t = 2 * x.t; - while (--i >= 0) - r[i] = 0; - for (i = 0; i < x.t - 1; ++i) { - var c = x.am(i, x[i], r, 2 * i, 0, 1); - if ( - (r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= - x.DV - ) { - r[i + x.t] -= x.DV; - r[i + x.t + 1] = 1; - } - } - if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1); - r.s = 0; - r.clamp(); + var x = this.abs(); + var i = (r.t = 2 * x.t); + while (--i >= 0) r[i] = 0; + for (i = 0; i < x.t - 1; ++i) { + var c = x.am(i, x[i], r, 2 * i, 0, 1); + if ( + (r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= + x.DV + ) { + r[i + x.t] -= x.DV; + r[i + x.t + 1] = 1; + } + } + if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1); + r.s = 0; + r.clamp(); } // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) // r != q, this != m. q or r may be null. function bnpDivRemTo(m, q, r) { - var pm = m.abs(); - if (pm.t <= 0) return; - var pt = this.abs(); - if (pt.t < pm.t) { - if (q != null) q.fromInt(0); - if (r != null) this.copyTo(r); - return; - } - if (r == null) r = nbi(); - var y = nbi(), ts = this.s, ms = m.s; - var nsh = this.DB - nbits(pm[pm.t - 1]); - // normalize modulus - if (nsh > 0) { - pm.lShiftTo(nsh, y); - pt.lShiftTo(nsh, r); - } else { - pm.copyTo(y); - pt.copyTo(r); - } - var ys = y.t; - var y0 = y[ys - 1]; - if (y0 == 0) return; - var yt = y0 * (1 << this.F1) + (ys > 1 ? y[ys - 2] >> this.F2 : 0); - var d1 = this.FV / yt, d2 = (1 << this.F1) / yt, e = 1 << this.F2; - var i = r.t, j = i - ys, t = q == null ? nbi() : q; - y.dlShiftTo(j, t); - if (r.compareTo(t) >= 0) { - r[r.t++] = 1; - r.subTo(t, r); - } - BigInteger.ONE.dlShiftTo(ys, t); - t.subTo(y, y); - // "negative" y so we can replace sub with am later - while (y.t < ys) - y[y.t++] = 0; - while (--j >= 0) { - // Estimate quotient digit - var qd = r[--i] == y0 - ? this.DM - : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2); - if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { - // Try it out - y.dlShiftTo(j, t); - r.subTo(t, r); - while (r[i] < --qd) r.subTo(t, r); - } - } - if (q != null) { - r.drShiftTo(ys, q); - if (ts != ms) BigInteger.ZERO.subTo(q, q); - } - r.t = ys; - r.clamp(); - if (nsh > 0) r.rShiftTo(nsh, r); - // Denormalize remainder - if (ts < 0) BigInteger.ZERO.subTo(r, r); + var pm = m.abs(); + if (pm.t <= 0) return; + var pt = this.abs(); + if (pt.t < pm.t) { + if (q != null) q.fromInt(0); + if (r != null) this.copyTo(r); + return; + } + if (r == null) r = nbi(); + var y = nbi(), + ts = this.s, + ms = m.s; + var nsh = this.DB - nbits(pm[pm.t - 1]); + // normalize modulus + if (nsh > 0) { + pm.lShiftTo(nsh, y); + pt.lShiftTo(nsh, r); + } else { + pm.copyTo(y); + pt.copyTo(r); + } + var ys = y.t; + var y0 = y[ys - 1]; + if (y0 == 0) return; + var yt = y0 * (1 << this.F1) + (ys > 1 ? y[ys - 2] >> this.F2 : 0); + var d1 = this.FV / yt, + d2 = (1 << this.F1) / yt, + e = 1 << this.F2; + var i = r.t, + j = i - ys, + t = q == null ? nbi() : q; + y.dlShiftTo(j, t); + if (r.compareTo(t) >= 0) { + r[r.t++] = 1; + r.subTo(t, r); + } + BigInteger.ONE.dlShiftTo(ys, t); + t.subTo(y, y); + // "negative" y so we can replace sub with am later + while (y.t < ys) y[y.t++] = 0; + while (--j >= 0) { + // Estimate quotient digit + var qd = + r[--i] == y0 ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2); + if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { + // Try it out + y.dlShiftTo(j, t); + r.subTo(t, r); + while (r[i] < --qd) r.subTo(t, r); + } + } + if (q != null) { + r.drShiftTo(ys, q); + if (ts != ms) BigInteger.ZERO.subTo(q, q); + } + r.t = ys; + r.clamp(); + if (nsh > 0) r.rShiftTo(nsh, r); + // Denormalize remainder + if (ts < 0) BigInteger.ZERO.subTo(r, r); } // (public) this mod a function bnMod(a) { - var r = nbi(); - this.abs().divRemTo(a, null, r); - if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r); - return r; + var r = nbi(); + this.abs().divRemTo(a, null, r); + if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r); + return r; } // (protected) return "-1/this % 2^DB"; useful for Mont. reduction @@ -518,161 +522,164 @@ function bnMod(a) { // should reduce x and y(2-xy) by m^2 at each step to keep size bounded. // JS multiply "overflows" differently from C/C++, so care is needed here. function bnpInvDigit() { - if (this.t < 1) return 0; - var x = this[0]; - if ((x & 1) == 0) return 0; - var y = x & 3; - // y == 1/x mod 2^2 - y = y * (2 - (x & 0xf) * y) & 0xf; - // y == 1/x mod 2^4 - y = y * (2 - (x & 0xff) * y) & 0xff; - // y == 1/x mod 2^8 - y = y * (2 - ((x & 0xffff) * y & 0xffff)) & 0xffff; - // y == 1/x mod 2^16 - // last step - calculate inverse mod DV directly; - // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints - y = y * (2 - x * y % this.DV) % this.DV; - // y == 1/x mod 2^dbits - // we really want the negative inverse, and -DV < y < DV - return y > 0 ? this.DV - y : -y; + if (this.t < 1) return 0; + var x = this[0]; + if ((x & 1) == 0) return 0; + var y = x & 3; + // y == 1/x mod 2^2 + y = (y * (2 - (x & 0xf) * y)) & 0xf; + // y == 1/x mod 2^4 + y = (y * (2 - (x & 0xff) * y)) & 0xff; + // y == 1/x mod 2^8 + y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; + // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y * (2 - ((x * y) % this.DV))) % this.DV; + // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return y > 0 ? this.DV - y : -y; } function bnEquals(a) { - return this.compareTo(a) == 0; + return this.compareTo(a) == 0; } // (protected) r = this + a function bnpAddTo(a, r) { - var i = 0, c = 0, m = Math.min(a.t, this.t); - while (i < m) { - c += this[i] + a[i]; - r[i++] = c & this.DM; - c >>= this.DB; - } - if (a.t < this.t) { - c += a.s; - while (i < this.t) { - c += this[i]; - r[i++] = c & this.DM; - c >>= this.DB; - } - c += this.s; - } else { - c += this.s; - while (i < a.t) { - c += a[i]; - r[i++] = c & this.DM; - c >>= this.DB; - } - c += a.s; - } - r.s = c < 0 ? -1 : 0; - if (c > 0) r[i++] = c; - else if (c < -1) r[i++] = this.DV + c; - r.t = i; - r.clamp(); + var i = 0, + c = 0, + m = Math.min(a.t, this.t); + while (i < m) { + c += this[i] + a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + if (a.t < this.t) { + c += a.s; + while (i < this.t) { + c += this[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += this.s; + } else { + c += this.s; + while (i < a.t) { + c += a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += a.s; + } + r.s = c < 0 ? -1 : 0; + if (c > 0) r[i++] = c; + else if (c < -1) r[i++] = this.DV + c; + r.t = i; + r.clamp(); } // (public) this + a function bnAdd(a) { - var r = nbi(); + var r = nbi(); - this.addTo(a, r); + this.addTo(a, r); - return r; + return r; } // (public) this - a function bnSubtract(a) { - var r = nbi(); + var r = nbi(); - this.subTo(a, r); + this.subTo(a, r); - return r; + return r; } // (public) this * a function bnMultiply(a) { - var r = nbi(); + var r = nbi(); - this.multiplyTo(a, r); + this.multiplyTo(a, r); - return r; + return r; } // (public) this / a function bnDivide(a) { - var r = nbi(); + var r = nbi(); - this.divRemTo(a, r, null); + this.divRemTo(a, r, null); - return r; + return r; } // Montgomery reduction function Montgomery(m) { - this.m = m; - this.mp = m.invDigit(); - this.mpl = this.mp & 0x7fff; - this.mph = this.mp >> 15; - this.um = (1 << m.DB - 15) - 1; - this.mt2 = 2 * m.t; + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp & 0x7fff; + this.mph = this.mp >> 15; + this.um = (1 << (m.DB - 15)) - 1; + this.mt2 = 2 * m.t; } // xR mod m function montConvert(x) { - var r = nbi(); - x.abs().dlShiftTo(this.m.t, r); - r.divRemTo(this.m, null, r); - if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r); - return r; + var r = nbi(); + x.abs().dlShiftTo(this.m.t, r); + r.divRemTo(this.m, null, r); + if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r); + return r; } // x/R mod m function montRevert(x) { - var r = nbi(); - x.copyTo(r); - this.reduce(r); - return r; + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; } // x = x/R mod m (HAC 14.32) function montReduce(x) { - while (x.t <= this.mt2) - // pad x so am has enough room later - x[x.t++] = 0; - for (var i = 0; i < this.m.t; ++i) { - // faster way of calculating u0 = x[i]*mp mod DV - var j = x[i] & 0x7fff; - var u0 = j * this.mpl + - ((j * this.mph + (x[i] >> 15) * this.mpl & this.um) << 15) & - x.DM; - // use am to combine the multiply-shift-add into one call - j = i + this.m.t; - x[j] += this.m.am(0, u0, x, i, 0, this.m.t); - // propagate carry - while (x[j] >= x.DV) { - x[j] -= x.DV; - x[++j]++; - } - } - x.clamp(); - x.drShiftTo(this.m.t, x); - if (x.compareTo(this.m) >= 0) x.subTo(this.m, x); + while (x.t <= this.mt2) + // pad x so am has enough room later + x[x.t++] = 0; + for (var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x[i] & 0x7fff; + var u0 = + (j * this.mpl + + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & + x.DM; + // use am to combine the multiply-shift-add into one call + j = i + this.m.t; + x[j] += this.m.am(0, u0, x, i, 0, this.m.t); + // propagate carry + while (x[j] >= x.DV) { + x[j] -= x.DV; + x[++j]++; + } + } + x.clamp(); + x.drShiftTo(this.m.t, x); + if (x.compareTo(this.m) >= 0) x.subTo(this.m, x); } // r = "x^2/R mod m"; x != r function montSqrTo(x, r) { - x.squareTo(r); + x.squareTo(r); - this.reduce(r); + this.reduce(r); } // r = "xy/R mod m"; x,y != r function montMulTo(x, y, r) { - x.multiplyTo(y, r); + x.multiplyTo(y, r); - this.reduce(r); + this.reduce(r); } Montgomery.prototype.convert = montConvert; @@ -683,78 +690,88 @@ Montgomery.prototype.sqrTo = montSqrTo; // (public) this^e % m (HAC 14.85) function bnModPow(e, m, callback) { - var i = e.bitLength(), k, r = nbv(1), z = new Montgomery(m); - if (i <= 0) return r; - else if (i < 18) k = 1; - else if (i < 48) k = 3; - else if (i < 144) k = 4; - else if (i < 768) k = 5; - else k = 6; - - // precomputation - var g = new Array(), n = 3, k1 = k - 1, km = (1 << k) - 1; - g[1] = z.convert(this); - if (k > 1) { - var g2 = nbi(); - z.sqrTo(g[1], g2); - while (n <= km) { - g[n] = nbi(); - z.mulTo(g2, g[n - 2], g[n]); - n += 2; - } - } - - var j = e.t - 1, w, is1 = true, r2 = nbi(), t; - i = nbits(e[j]) - 1; - while (j >= 0) { - if (i >= k1) w = e[j] >> i - k1 & km; - else { - w = (e[j] & (1 << i + 1) - 1) << k1 - i; - if (j > 0) w |= e[j - 1] >> this.DB + i - k1; - } - - n = k; - while ((w & 1) == 0) { - w >>= 1; - --n; - } - if ((i -= n) < 0) { - i += this.DB; - --j; - } - if (is1) { - // ret == 1, don't bother squaring or multiplying it - g[w].copyTo(r); - is1 = false; - } else { - while (n > 1) { - z.sqrTo(r, r2); - z.sqrTo(r2, r); - n -= 2; - } - if (n > 0) z.sqrTo(r, r2); - else { - t = r; - r = r2; - r2 = t; - } - z.mulTo(r2, g[w], r); - } - - while (j >= 0 && (e[j] & 1 << i) == 0) { - z.sqrTo(r, r2); - t = r; - r = r2; - r2 = t; - if (--i < 0) { - i = this.DB - 1; - --j; - } - } - } - var result = z.revert(r); - callback(null, result); - return result; + var i = e.bitLength(), + k, + r = nbv(1), + z = new Montgomery(m); + if (i <= 0) return r; + else if (i < 18) k = 1; + else if (i < 48) k = 3; + else if (i < 144) k = 4; + else if (i < 768) k = 5; + else k = 6; + + // precomputation + var g = new Array(), + n = 3, + k1 = k - 1, + km = (1 << k) - 1; + g[1] = z.convert(this); + if (k > 1) { + var g2 = nbi(); + z.sqrTo(g[1], g2); + while (n <= km) { + g[n] = nbi(); + z.mulTo(g2, g[n - 2], g[n]); + n += 2; + } + } + + var j = e.t - 1, + w, + is1 = true, + r2 = nbi(), + t; + i = nbits(e[j]) - 1; + while (j >= 0) { + if (i >= k1) w = (e[j] >> (i - k1)) & km; + else { + w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i); + if (j > 0) w |= e[j - 1] >> (this.DB + i - k1); + } + + n = k; + while ((w & 1) == 0) { + w >>= 1; + --n; + } + if ((i -= n) < 0) { + i += this.DB; + --j; + } + if (is1) { + // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r); + is1 = false; + } else { + while (n > 1) { + z.sqrTo(r, r2); + z.sqrTo(r2, r); + n -= 2; + } + if (n > 0) z.sqrTo(r, r2); + else { + t = r; + r = r2; + r2 = t; + } + z.mulTo(r2, g[w], r); + } + + while (j >= 0 && (e[j] & (1 << i)) == 0) { + z.sqrTo(r, r2); + t = r; + r = r2; + r2 = t; + if (--i < 0) { + i = this.DB - 1; + --j; + } + } + } + var result = z.revert(r); + callback(null, result); + return result; } // protected @@ -790,4 +807,3 @@ BigInteger.prototype.modPow = bnModPow; // "constants" BigInteger.ZERO = nbv(0); BigInteger.ONE = nbv(1); - diff --git a/packages/amazon-cognito-identity-js/src/Client.js b/packages/amazon-cognito-identity-js/src/Client.js index 77fa88fec3e..ac81442aae7 100644 --- a/packages/amazon-cognito-identity-js/src/Client.js +++ b/packages/amazon-cognito-identity-js/src/Client.js @@ -1,96 +1,103 @@ import UserAgent from './UserAgent'; /** @class */ export default class Client { - /** - * Constructs a new AWS Cognito Identity Provider client object - * @param {string} region AWS region - * @param {string} endpoint endpoint - */ - constructor(region, endpoint) { - this.endpoint = endpoint || `https://cognito-idp.${region}.amazonaws.com/`; - this.userAgent = UserAgent.prototype.userAgent || 'aws-amplify/0.1.x js'; - } + /** + * Constructs a new AWS Cognito Identity Provider client object + * @param {string} region AWS region + * @param {string} endpoint endpoint + */ + constructor(region, endpoint) { + this.endpoint = endpoint || `https://cognito-idp.${region}.amazonaws.com/`; + this.userAgent = UserAgent.prototype.userAgent || 'aws-amplify/0.1.x js'; + } - /** - * Makes an unauthenticated request on AWS Cognito Identity Provider API - * using fetch - * @param {string} operation API operation - * @param {object} params Input parameters - * @param {function} callback Callback called when a response is returned - * @returns {void} - */ - request(operation, params, callback) { - const headers = { - 'Content-Type': 'application/x-amz-json-1.1', - 'X-Amz-Target': `AWSCognitoIdentityProviderService.${operation}`, - 'X-Amz-User-Agent': this.userAgent, - }; + /** + * Makes an unauthenticated request on AWS Cognito Identity Provider API + * using fetch + * @param {string} operation API operation + * @param {object} params Input parameters + * @param {function} callback Callback called when a response is returned + * @returns {void} + */ + request(operation, params, callback) { + const headers = { + 'Content-Type': 'application/x-amz-json-1.1', + 'X-Amz-Target': `AWSCognitoIdentityProviderService.${operation}`, + 'X-Amz-User-Agent': this.userAgent, + }; - const options = { - headers, - method: 'POST', - mode: 'cors', - cache: 'no-cache', - body: JSON.stringify(params), - }; + const options = { + headers, + method: 'POST', + mode: 'cors', + cache: 'no-cache', + body: JSON.stringify(params), + }; - let response; - let responseJsonData; + let response; + let responseJsonData; - fetch(this.endpoint, options) - .then(resp => { - response = resp; - return resp; - }, err => { - // If error happens here, the request failed - // if it is TypeError throw network error - if (err instanceof TypeError) { - throw new Error('Network error'); - } - throw err; - }) - .then(resp => resp.json().catch(() => ({}))) - .then(data => { - // return parsed body stream - if (response.ok) return callback(null, data); - responseJsonData = data; + fetch(this.endpoint, options) + .then( + resp => { + response = resp; + return resp; + }, + err => { + // If error happens here, the request failed + // if it is TypeError throw network error + if (err instanceof TypeError) { + throw new Error('Network error'); + } + throw err; + } + ) + .then(resp => resp.json().catch(() => ({}))) + .then(data => { + // return parsed body stream + if (response.ok) return callback(null, data); + responseJsonData = data; - // Taken from aws-sdk-js/lib/protocol/json.js - // eslint-disable-next-line no-underscore-dangle - const code = (data.__type || data.code).split('#').pop(); - const error = { - code, - name: code, - message: (data.message || data.Message || null), - }; - return callback(error); - }) - .catch(err => { - // first check if we have a service error - if (response && response.headers && response.headers.get('x-amzn-errortype')) { - try { - const code = (response.headers.get('x-amzn-errortype')).split(':')[0]; - const error = { - code, - name: code, - statusCode: response.status, - message: (response.status) ? response.status.toString() : null, - }; - return callback(error); - } catch (ex) { - return callback(err); - } - // otherwise check if error is Network error - } else if (err instanceof Error && err.message === 'Network error') { - const error = { - code: 'NetworkError', - name: err.name, - message: err.message, - }; - return callback(error); - } else { - return callback(err); - } - }); - } + // Taken from aws-sdk-js/lib/protocol/json.js + // eslint-disable-next-line no-underscore-dangle + const code = (data.__type || data.code).split('#').pop(); + const error = { + code, + name: code, + message: data.message || data.Message || null, + }; + return callback(error); + }) + .catch(err => { + // first check if we have a service error + if ( + response && + response.headers && + response.headers.get('x-amzn-errortype') + ) { + try { + const code = response.headers.get('x-amzn-errortype').split(':')[0]; + const error = { + code, + name: code, + statusCode: response.status, + message: response.status ? response.status.toString() : null, + }; + return callback(error); + } catch (ex) { + return callback(err); + } + // otherwise check if error is Network error + } else if (err instanceof Error && err.message === 'Network error') { + const error = { + code: 'NetworkError', + name: err.name, + message: err.message, + }; + return callback(error); + } else { + return callback(err); + } + }); + } } diff --git a/packages/amazon-cognito-identity-js/src/CognitoAccessToken.js b/packages/amazon-cognito-identity-js/src/CognitoAccessToken.js index 9bea85eee90..ed92668e783 100644 --- a/packages/amazon-cognito-identity-js/src/CognitoAccessToken.js +++ b/packages/amazon-cognito-identity-js/src/CognitoAccessToken.js @@ -19,11 +19,11 @@ import CognitoJwtToken from './CognitoJwtToken'; /** @class */ export default class CognitoAccessToken extends CognitoJwtToken { - /** - * Constructs a new CognitoAccessToken object - * @param {string=} AccessToken The JWT access token. - */ - constructor({ AccessToken } = {}) { - super(AccessToken || ''); - } + /** + * Constructs a new CognitoAccessToken object + * @param {string=} AccessToken The JWT access token. + */ + constructor({ AccessToken } = {}) { + super(AccessToken || ''); + } } diff --git a/packages/amazon-cognito-identity-js/src/CognitoIdToken.js b/packages/amazon-cognito-identity-js/src/CognitoIdToken.js index 35e2a2951f7..a6f44092eda 100644 --- a/packages/amazon-cognito-identity-js/src/CognitoIdToken.js +++ b/packages/amazon-cognito-identity-js/src/CognitoIdToken.js @@ -19,11 +19,11 @@ import CognitoJwtToken from './CognitoJwtToken'; /** @class */ export default class CognitoIdToken extends CognitoJwtToken { - /** - * Constructs a new CognitoIdToken object - * @param {string=} IdToken The JWT Id token - */ - constructor({ IdToken } = {}) { - super(IdToken || ''); - } + /** + * Constructs a new CognitoIdToken object + * @param {string=} IdToken The JWT Id token + */ + constructor({ IdToken } = {}) { + super(IdToken || ''); + } } diff --git a/packages/amazon-cognito-identity-js/src/CognitoJwtToken.js b/packages/amazon-cognito-identity-js/src/CognitoJwtToken.js index d02858d0fbf..763e8dd2f68 100644 --- a/packages/amazon-cognito-identity-js/src/CognitoJwtToken.js +++ b/packages/amazon-cognito-identity-js/src/CognitoJwtToken.js @@ -19,46 +19,46 @@ import { Buffer } from 'buffer/'; /** @class */ export default class CognitoJwtToken { - /** - * Constructs a new CognitoJwtToken object - * @param {string=} token The JWT token. - */ - constructor(token) { - // Assign object - this.jwtToken = token || ''; - this.payload = this.decodePayload(); - } + /** + * Constructs a new CognitoJwtToken object + * @param {string=} token The JWT token. + */ + constructor(token) { + // Assign object + this.jwtToken = token || ''; + this.payload = this.decodePayload(); + } - /** - * @returns {string} the record's token. - */ - getJwtToken() { - return this.jwtToken; - } + /** + * @returns {string} the record's token. + */ + getJwtToken() { + return this.jwtToken; + } - /** - * @returns {int} the token's expiration (exp member). - */ - getExpiration() { - return this.payload.exp; - } + /** + * @returns {int} the token's expiration (exp member). + */ + getExpiration() { + return this.payload.exp; + } - /** - * @returns {int} the token's "issued at" (iat member). - */ - getIssuedAt() { - return this.payload.iat; - } + /** + * @returns {int} the token's "issued at" (iat member). + */ + getIssuedAt() { + return this.payload.iat; + } - /** - * @returns {object} the token's payload. - */ - decodePayload() { - const payload = this.jwtToken.split('.')[1]; - try { - return JSON.parse(Buffer.from(payload, 'base64').toString('utf8')); - } catch (err) { - return {}; - } - } + /** + * @returns {object} the token's payload. + */ + decodePayload() { + const payload = this.jwtToken.split('.')[1]; + try { + return JSON.parse(Buffer.from(payload, 'base64').toString('utf8')); + } catch (err) { + return {}; + } + } } diff --git a/packages/amazon-cognito-identity-js/src/CognitoRefreshToken.js b/packages/amazon-cognito-identity-js/src/CognitoRefreshToken.js index 2775e098aec..577a7229161 100644 --- a/packages/amazon-cognito-identity-js/src/CognitoRefreshToken.js +++ b/packages/amazon-cognito-identity-js/src/CognitoRefreshToken.js @@ -17,19 +17,19 @@ /** @class */ export default class CognitoRefreshToken { - /** - * Constructs a new CognitoRefreshToken object - * @param {string=} RefreshToken The JWT refresh token. - */ - constructor({ RefreshToken } = {}) { - // Assign object - this.token = RefreshToken || ''; - } + /** + * Constructs a new CognitoRefreshToken object + * @param {string=} RefreshToken The JWT refresh token. + */ + constructor({ RefreshToken } = {}) { + // Assign object + this.token = RefreshToken || ''; + } - /** - * @returns {string} the record's token. - */ - getToken() { - return this.token; - } + /** + * @returns {string} the record's token. + */ + getToken() { + return this.token; + } } diff --git a/packages/amazon-cognito-identity-js/src/CognitoUser.js b/packages/amazon-cognito-identity-js/src/CognitoUser.js index e4f6a10221e..7d841ca0b82 100644 --- a/packages/amazon-cognito-identity-js/src/CognitoUser.js +++ b/packages/amazon-cognito-identity-js/src/CognitoUser.js @@ -70,1723 +70,1927 @@ import StorageHelper from './StorageHelper'; * @param {bool=} userConfirmationNecessary User must be confirmed. */ - /** @class */ export default class CognitoUser { - /** - * Constructs a new CognitoUser object - * @param {object} data Creation options - * @param {string} data.Username The user's username. - * @param {CognitoUserPool} data.Pool Pool containing the user. - * @param {object} data.Storage Optional storage object. - */ - constructor(data) { - if (data == null || data.Username == null || data.Pool == null) { - throw new Error('Username and pool information are required.'); - } - - this.username = data.Username || ''; - this.pool = data.Pool; - this.Session = null; - - this.client = data.Pool.client; - - this.signInUserSession = null; - this.authenticationFlowType = 'USER_SRP_AUTH'; - - this.storage = data.Storage || new StorageHelper().getStorage(); - - this.keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}`; - this.userDataKey = `${this.keyPrefix}.${this.username}.userData`; - } - - /** - * Sets the session for this user - * @param {CognitoUserSession} signInUserSession the session - * @returns {void} - */ - setSignInUserSession(signInUserSession) { - this.clearCachedUserData(); - this.signInUserSession = signInUserSession; - this.cacheTokens(); - } - - /** - * @returns {CognitoUserSession} the current session for this user - */ - getSignInUserSession() { - return this.signInUserSession; - } - - /** - * @returns {string} the user's username - */ - getUsername() { - return this.username; - } - - /** - * @returns {String} the authentication flow type - */ - getAuthenticationFlowType() { - return this.authenticationFlowType; - } - - /** - * sets authentication flow type - * @param {string} authenticationFlowType New value. - * @returns {void} - */ - setAuthenticationFlowType(authenticationFlowType) { - this.authenticationFlowType = authenticationFlowType; - } - - - /** - * This is used for authenticating the user through the custom authentication flow. - * @param {AuthenticationDetails} authDetails Contains the authentication data - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {customChallenge} callback.customChallenge Custom challenge - * response required to continue. - * @param {authSuccess} callback.onSuccess Called on success with the new session. - * @returns {void} - */ - initiateAuth(authDetails, callback) { - const authParameters = authDetails.getAuthParameters(); - authParameters.USERNAME = this.username; - - const jsonReq = { - AuthFlow: 'CUSTOM_AUTH', - ClientId: this.pool.getClientId(), - AuthParameters: authParameters, - ClientMetadata: authDetails.getValidationData(), - }; - if (this.getUserContextData()) { - jsonReq.UserContextData = this.getUserContextData(); - } - - this.client.request('InitiateAuth', jsonReq, (err, data) => { - if (err) { - return callback.onFailure(err); - } - const challengeName = data.ChallengeName; - const challengeParameters = data.ChallengeParameters; - - if (challengeName === 'CUSTOM_CHALLENGE') { - this.Session = data.Session; - return callback.customChallenge(challengeParameters); - } - this.signInUserSession = this.getCognitoUserSession(data.AuthenticationResult); - this.cacheTokens(); - return callback.onSuccess(this.signInUserSession); - }); - } - - /** - * This is used for authenticating the user. - * stuff - * @param {AuthenticationDetails} authDetails Contains the authentication data - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {newPasswordRequired} callback.newPasswordRequired new - * password and any required attributes are required to continue - * @param {mfaRequired} callback.mfaRequired MFA code - * required to continue. - * @param {customChallenge} callback.customChallenge Custom challenge - * response required to continue. - * @param {authSuccess} callback.onSuccess Called on success with the new session. - * @returns {void} - */ - authenticateUser(authDetails, callback) { - if (this.authenticationFlowType === 'USER_PASSWORD_AUTH') { - return this.authenticateUserPlainUsernamePassword(authDetails, callback); - } else if (this.authenticationFlowType === 'USER_SRP_AUTH' || this.authenticationFlowType === 'CUSTOM_AUTH') { - return this.authenticateUserDefaultAuth(authDetails, callback); - } - return callback.onFailure(new Error('Authentication flow type is invalid.')); - } - - /** - * PRIVATE ONLY: This is an internal only method and should not - * be directly called by the consumers. - * It calls the AuthenticationHelper for SRP related - * stuff - * @param {AuthenticationDetails} authDetails Contains the authentication data - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {newPasswordRequired} callback.newPasswordRequired new - * password and any required attributes are required to continue - * @param {mfaRequired} callback.mfaRequired MFA code - * required to continue. - * @param {customChallenge} callback.customChallenge Custom challenge - * response required to continue. - * @param {authSuccess} callback.onSuccess Called on success with the new session. - * @returns {void} - */ - authenticateUserDefaultAuth(authDetails, callback) { - const authenticationHelper = new AuthenticationHelper( - this.pool.getUserPoolId().split('_')[1]); - const dateHelper = new DateHelper(); - - let serverBValue; - let salt; - const authParameters = {}; - - if (this.deviceKey != null) { - authParameters.DEVICE_KEY = this.deviceKey; - } - - authParameters.USERNAME = this.username; - authenticationHelper.getLargeAValue((errOnAValue, aValue) => { - // getLargeAValue callback start - if (errOnAValue) { - callback.onFailure(errOnAValue); - } - - authParameters.SRP_A = aValue.toString(16); - - if (this.authenticationFlowType === 'CUSTOM_AUTH') { - authParameters.CHALLENGE_NAME = 'SRP_A'; - } - - const jsonReq = { - AuthFlow: this.authenticationFlowType, - ClientId: this.pool.getClientId(), - AuthParameters: authParameters, - ClientMetadata: authDetails.getValidationData(), - }; - if (this.getUserContextData(this.username)) { - jsonReq.UserContextData = this.getUserContextData(this.username); - } - - this.client.request('InitiateAuth', jsonReq, (err, data) => { - if (err) { - return callback.onFailure(err); - } - - const challengeParameters = data.ChallengeParameters; - - this.username = challengeParameters.USER_ID_FOR_SRP; - serverBValue = new BigInteger(challengeParameters.SRP_B, 16); - salt = new BigInteger(challengeParameters.SALT, 16); - this.getCachedDeviceKeyAndPassword(); - - authenticationHelper.getPasswordAuthenticationKey( - this.username, - authDetails.getPassword(), - serverBValue, - salt, - (errOnHkdf, hkdf) => { - // getPasswordAuthenticationKey callback start - if (errOnHkdf) { - callback.onFailure(errOnHkdf); - } - - const dateNow = dateHelper.getNowString(); - - const message = CryptoJS.lib.WordArray.create( - Buffer.concat([ - Buffer.from(this.pool.getUserPoolId().split('_')[1], 'utf8'), - Buffer.from(this.username, 'utf8'), - Buffer.from(challengeParameters.SECRET_BLOCK, 'base64'), - Buffer.from(dateNow, 'utf8'), - ]) - ); - const key = CryptoJS.lib.WordArray.create(hkdf); - const signatureString = Base64.stringify(HmacSHA256(message, key)); - - const challengeResponses = {}; - - challengeResponses.USERNAME = this.username; - challengeResponses.PASSWORD_CLAIM_SECRET_BLOCK = challengeParameters.SECRET_BLOCK; - challengeResponses.TIMESTAMP = dateNow; - challengeResponses.PASSWORD_CLAIM_SIGNATURE = signatureString; - - if (this.deviceKey != null) { - challengeResponses.DEVICE_KEY = this.deviceKey; - } - - const respondToAuthChallenge = (challenge, challengeCallback) => - this.client.request('RespondToAuthChallenge', challenge, - (errChallenge, dataChallenge) => { - if (errChallenge && errChallenge.code === 'ResourceNotFoundException' && - errChallenge.message.toLowerCase().indexOf('device') !== -1) { - challengeResponses.DEVICE_KEY = null; - this.deviceKey = null; - this.randomPassword = null; - this.deviceGroupKey = null; - this.clearCachedDeviceKeyAndPassword(); - return respondToAuthChallenge(challenge, challengeCallback); - } - return challengeCallback(errChallenge, dataChallenge); - }); - - const jsonReqResp = { - ChallengeName: 'PASSWORD_VERIFIER', - ClientId: this.pool.getClientId(), - ChallengeResponses: challengeResponses, - Session: data.Session, - }; - if (this.getUserContextData()) { - jsonReqResp.UserContextData = this.getUserContextData(); - } - respondToAuthChallenge(jsonReqResp, (errAuthenticate, dataAuthenticate) => { - if (errAuthenticate) { - return callback.onFailure(errAuthenticate); - } - - return this.authenticateUserInternal( - dataAuthenticate, - authenticationHelper, - callback - ); - }); - return undefined; - // getPasswordAuthenticationKey callback end - }); - return undefined; - }); - // getLargeAValue callback end - }); - } - - /** - * PRIVATE ONLY: This is an internal only method and should not - * be directly called by the consumers. - * @param {AuthenticationDetails} authDetails Contains the authentication data. - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {mfaRequired} callback.mfaRequired MFA code - * required to continue. - * @param {authSuccess} callback.onSuccess Called on success with the new session. - * @returns {void} - */ - authenticateUserPlainUsernamePassword(authDetails, callback) { - const authParameters = {}; - authParameters.USERNAME = this.username; - authParameters.PASSWORD = authDetails.getPassword(); - if (!authParameters.PASSWORD) { - callback.onFailure(new Error('PASSWORD parameter is required')); - return; - } - const authenticationHelper = new AuthenticationHelper( - this.pool.getUserPoolId().split('_')[1]); - this.getCachedDeviceKeyAndPassword(); - if (this.deviceKey != null) { - authParameters.DEVICE_KEY = this.deviceKey; - } - - const jsonReq = { - AuthFlow: 'USER_PASSWORD_AUTH', - ClientId: this.pool.getClientId(), - AuthParameters: authParameters, - ClientMetadata: authDetails.getValidationData(), - }; - if (this.getUserContextData(this.username)) { - jsonReq.UserContextData = this.getUserContextData(this.username); - } - // USER_PASSWORD_AUTH happens in a single round-trip: client sends userName and password, - // Cognito UserPools verifies password and returns tokens. - this.client.request('InitiateAuth', jsonReq, (err, authResult) => { - if (err) { - return callback.onFailure(err); - } - return this.authenticateUserInternal(authResult, authenticationHelper, callback); - }); - } - - /** - * PRIVATE ONLY: This is an internal only method and should not - * be directly called by the consumers. - * @param {object} dataAuthenticate authentication data - * @param {object} authenticationHelper helper created - * @param {callback} callback passed on from caller - * @returns {void} - */ - authenticateUserInternal(dataAuthenticate, authenticationHelper, callback) { - const challengeName = dataAuthenticate.ChallengeName; - const challengeParameters = dataAuthenticate.ChallengeParameters; - - if (challengeName === 'SMS_MFA') { - this.Session = dataAuthenticate.Session; - return callback.mfaRequired(challengeName, challengeParameters); - } - - if (challengeName === 'SELECT_MFA_TYPE') { - this.Session = dataAuthenticate.Session; - return callback.selectMFAType(challengeName, challengeParameters); - } - - if (challengeName === 'MFA_SETUP') { - this.Session = dataAuthenticate.Session; - return callback.mfaSetup(challengeName, challengeParameters); - } - - if (challengeName === 'SOFTWARE_TOKEN_MFA') { - this.Session = dataAuthenticate.Session; - return callback.totpRequired(challengeName, challengeParameters); - } - - if (challengeName === 'CUSTOM_CHALLENGE') { - this.Session = dataAuthenticate.Session; - return callback.customChallenge(challengeParameters); - } - - if (challengeName === 'NEW_PASSWORD_REQUIRED') { - this.Session = dataAuthenticate.Session; - - let userAttributes = null; - let rawRequiredAttributes = null; - const requiredAttributes = []; - const userAttributesPrefix = authenticationHelper - .getNewPasswordRequiredChallengeUserAttributePrefix(); - - if (challengeParameters) { - userAttributes = JSON.parse( - dataAuthenticate.ChallengeParameters.userAttributes); - rawRequiredAttributes = JSON.parse( - dataAuthenticate.ChallengeParameters.requiredAttributes); - } - - if (rawRequiredAttributes) { - for (let i = 0; i < rawRequiredAttributes.length; i++) { - requiredAttributes[i] = rawRequiredAttributes[i].substr( - userAttributesPrefix.length - ); - } - } - return callback.newPasswordRequired(userAttributes, requiredAttributes); - } - - if (challengeName === 'DEVICE_SRP_AUTH') { - this.getDeviceResponse(callback); - return undefined; - } - - this.signInUserSession = this.getCognitoUserSession(dataAuthenticate.AuthenticationResult); - this.challengeName = challengeName; - this.cacheTokens(); - - const newDeviceMetadata = dataAuthenticate.AuthenticationResult.NewDeviceMetadata; - if (newDeviceMetadata == null) { - return callback.onSuccess(this.signInUserSession); - } - - authenticationHelper.generateHashDevice( - dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceGroupKey, - dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey, - (errGenHash) => { - if (errGenHash) { - return callback.onFailure(errGenHash); - } - - const deviceSecretVerifierConfig = { - Salt: Buffer.from( - authenticationHelper.getSaltDevices(), 'hex' - ).toString('base64'), - PasswordVerifier: Buffer.from( - authenticationHelper.getVerifierDevices(), 'hex' - ).toString('base64'), - }; - - this.verifierDevices = deviceSecretVerifierConfig.PasswordVerifier; - this.deviceGroupKey = newDeviceMetadata.DeviceGroupKey; - this.randomPassword = authenticationHelper.getRandomPassword(); - - this.client.request('ConfirmDevice', { - DeviceKey: newDeviceMetadata.DeviceKey, - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - DeviceSecretVerifierConfig: deviceSecretVerifierConfig, - DeviceName: navigator.userAgent, - }, (errConfirm, dataConfirm) => { - if (errConfirm) { - return callback.onFailure(errConfirm); - } - - this.deviceKey = dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey; - this.cacheDeviceKeyAndPassword(); - if (dataConfirm.UserConfirmationNecessary === true) { - return callback.onSuccess( - this.signInUserSession, dataConfirm.UserConfirmationNecessary); - } - return callback.onSuccess(this.signInUserSession); - }); - return undefined; - }); - return undefined; - } - - /** - * This method is user to complete the NEW_PASSWORD_REQUIRED challenge. - * Pass the new password with any new user attributes to be updated. - * User attribute keys must be of format userAttributes.. - * @param {string} newPassword new password for this user - * @param {object} requiredAttributeData map with values for all required attributes - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {mfaRequired} callback.mfaRequired MFA code required to continue. - * @param {customChallenge} callback.customChallenge Custom challenge - * response required to continue. - * @param {authSuccess} callback.onSuccess Called on success with the new session. - * @returns {void} - */ - completeNewPasswordChallenge(newPassword, requiredAttributeData, callback) { - if (!newPassword) { - return callback.onFailure(new Error('New password is required.')); - } - const authenticationHelper = new AuthenticationHelper( - this.pool.getUserPoolId().split('_')[1]); - const userAttributesPrefix = authenticationHelper - .getNewPasswordRequiredChallengeUserAttributePrefix(); - - const finalUserAttributes = {}; - if (requiredAttributeData) { - Object.keys(requiredAttributeData).forEach((key) => { - finalUserAttributes[userAttributesPrefix + key] = requiredAttributeData[key]; - }); - } - - finalUserAttributes.NEW_PASSWORD = newPassword; - finalUserAttributes.USERNAME = this.username; - const jsonReq = { - ChallengeName: 'NEW_PASSWORD_REQUIRED', - ClientId: this.pool.getClientId(), - ChallengeResponses: finalUserAttributes, - Session: this.Session, - }; - if (this.getUserContextData()) { - jsonReq.UserContextData = this.getUserContextData(); - } - - this.client.request('RespondToAuthChallenge', - jsonReq, (errAuthenticate, dataAuthenticate) => { - if (errAuthenticate) { - return callback.onFailure(errAuthenticate); - } - return this.authenticateUserInternal(dataAuthenticate, authenticationHelper, callback); - }); - return undefined; - } - - /** - * This is used to get a session using device authentication. It is called at the end of user - * authentication - * - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {authSuccess} callback.onSuccess Called on success with the new session. - * @returns {void} - * @private - */ - getDeviceResponse(callback) { - const authenticationHelper = new AuthenticationHelper( - this.deviceGroupKey); - const dateHelper = new DateHelper(); - - const authParameters = {}; - - authParameters.USERNAME = this.username; - authParameters.DEVICE_KEY = this.deviceKey; - authenticationHelper.getLargeAValue((errAValue, aValue) => { - // getLargeAValue callback start - if (errAValue) { - callback.onFailure(errAValue); - } - - authParameters.SRP_A = aValue.toString(16); - - const jsonReq = { - ChallengeName: 'DEVICE_SRP_AUTH', - ClientId: this.pool.getClientId(), - ChallengeResponses: authParameters, - }; - if (this.getUserContextData()) { - jsonReq.UserContextData = this.getUserContextData(); - } - this.client.request('RespondToAuthChallenge', jsonReq, (err, data) => { - if (err) { - return callback.onFailure(err); - } - - const challengeParameters = data.ChallengeParameters; - - const serverBValue = new BigInteger(challengeParameters.SRP_B, 16); - const salt = new BigInteger(challengeParameters.SALT, 16); - - authenticationHelper.getPasswordAuthenticationKey( - this.deviceKey, - this.randomPassword, - serverBValue, - salt, - (errHkdf, hkdf) => { - // getPasswordAuthenticationKey callback start - if (errHkdf) { - return callback.onFailure(errHkdf); - } - - const dateNow = dateHelper.getNowString(); - - const message = CryptoJS.lib.WordArray.create( - Buffer.concat([ - Buffer.from(this.deviceGroupKey, 'utf8'), - Buffer.from(this.deviceKey, 'utf8'), - Buffer.from(challengeParameters.SECRET_BLOCK, 'base64'), - Buffer.from(dateNow, 'utf8'), - ]) - ); - const key = CryptoJS.lib.WordArray.create(hkdf); - const signatureString = Base64.stringify(HmacSHA256(message, key)); - - const challengeResponses = {}; - - challengeResponses.USERNAME = this.username; - challengeResponses.PASSWORD_CLAIM_SECRET_BLOCK = challengeParameters.SECRET_BLOCK; - challengeResponses.TIMESTAMP = dateNow; - challengeResponses.PASSWORD_CLAIM_SIGNATURE = signatureString; - challengeResponses.DEVICE_KEY = this.deviceKey; - - const jsonReqResp = { - ChallengeName: 'DEVICE_PASSWORD_VERIFIER', - ClientId: this.pool.getClientId(), - ChallengeResponses: challengeResponses, - Session: data.Session, - }; - if (this.getUserContextData()) { - jsonReqResp.UserContextData = this.getUserContextData(); - } - - this.client.request('RespondToAuthChallenge', - jsonReqResp, (errAuthenticate, dataAuthenticate) => { - if (errAuthenticate) { - return callback.onFailure(errAuthenticate); - } - - this.signInUserSession = this.getCognitoUserSession( - dataAuthenticate.AuthenticationResult - ); - this.cacheTokens(); - - return callback.onSuccess(this.signInUserSession); - }); - return undefined; - // getPasswordAuthenticationKey callback end - }); - return undefined; - }); - // getLargeAValue callback end - }); - } - - /** - * This is used for a certain user to confirm the registration by using a confirmation code - * @param {string} confirmationCode Code entered by user. - * @param {bool} forceAliasCreation Allow migrating from an existing email / phone number. - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - confirmRegistration(confirmationCode, forceAliasCreation, callback) { - const jsonReq = { - ClientId: this.pool.getClientId(), - ConfirmationCode: confirmationCode, - Username: this.username, - ForceAliasCreation: forceAliasCreation, - }; - if (this.getUserContextData()) { - jsonReq.UserContextData = this.getUserContextData(); - } - this.client.request('ConfirmSignUp', jsonReq, err => { - if (err) { - return callback(err, null); - } - return callback(null, 'SUCCESS'); - }); - } - - /** - * This is used by the user once he has the responses to a custom challenge - * @param {string} answerChallenge The custom challenge answer. - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {customChallenge} callback.customChallenge - * Custom challenge response required to continue. - * @param {authSuccess} callback.onSuccess Called on success with the new session. - * @returns {void} - */ - sendCustomChallengeAnswer(answerChallenge, callback) { - const challengeResponses = {}; - challengeResponses.USERNAME = this.username; - challengeResponses.ANSWER = answerChallenge; - - const authenticationHelper = new AuthenticationHelper( - this.pool.getUserPoolId().split('_')[1] - ); - this.getCachedDeviceKeyAndPassword(); - if (this.deviceKey != null) { - challengeResponses.DEVICE_KEY = this.deviceKey; - } - - const jsonReq = { - ChallengeName: 'CUSTOM_CHALLENGE', - ChallengeResponses: challengeResponses, - ClientId: this.pool.getClientId(), - Session: this.Session, - }; - if (this.getUserContextData()) { - jsonReq.UserContextData = this.getUserContextData(); - } - this.client.request('RespondToAuthChallenge', jsonReq, (err, data) => { - if (err) { - return callback.onFailure(err); - } - - return this.authenticateUserInternal(data, authenticationHelper, callback); - }); - } - - /** - * This is used by the user once he has an MFA code - * @param {string} confirmationCode The MFA code entered by the user. - * @param {object} callback Result callback map. - * @param {string} mfaType The mfa we are replying to. - * @param {onFailure} callback.onFailure Called on any error. - * @param {authSuccess} callback.onSuccess Called on success with the new session. - * @returns {void} - */ - sendMFACode(confirmationCode, callback, mfaType) { - const challengeResponses = {}; - challengeResponses.USERNAME = this.username; - challengeResponses.SMS_MFA_CODE = confirmationCode; - const mfaTypeSelection = mfaType || 'SMS_MFA'; - if (mfaTypeSelection === 'SOFTWARE_TOKEN_MFA') { - challengeResponses.SOFTWARE_TOKEN_MFA_CODE = confirmationCode; - } - - if (this.deviceKey != null) { - challengeResponses.DEVICE_KEY = this.deviceKey; - } - - const jsonReq = { - ChallengeName: mfaTypeSelection, - ChallengeResponses: challengeResponses, - ClientId: this.pool.getClientId(), - Session: this.Session, - }; - if (this.getUserContextData()) { - jsonReq.UserContextData = this.getUserContextData(); - } - - this.client.request('RespondToAuthChallenge', - jsonReq, (err, dataAuthenticate) => { - if (err) { - return callback.onFailure(err); - } - - const challengeName = dataAuthenticate.ChallengeName; - - if (challengeName === 'DEVICE_SRP_AUTH') { - this.getDeviceResponse(callback); - return undefined; - } - - this.signInUserSession = - this.getCognitoUserSession(dataAuthenticate.AuthenticationResult); - this.cacheTokens(); - - if (dataAuthenticate.AuthenticationResult.NewDeviceMetadata == null) { - return callback.onSuccess(this.signInUserSession); - } - - const authenticationHelper = new AuthenticationHelper( - this.pool.getUserPoolId().split('_')[1]); - authenticationHelper.generateHashDevice( - dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceGroupKey, - dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey, - (errGenHash) => { - if (errGenHash) { - return callback.onFailure(errGenHash); - } - - const deviceSecretVerifierConfig = { - Salt: Buffer.from( - authenticationHelper.getSaltDevices(), 'hex' - ).toString('base64'), - PasswordVerifier: Buffer.from( - authenticationHelper.getVerifierDevices(), 'hex' - ).toString('base64'), - }; - - this.verifierDevices = deviceSecretVerifierConfig.PasswordVerifier; - this.deviceGroupKey = dataAuthenticate.AuthenticationResult - .NewDeviceMetadata.DeviceGroupKey; - this.randomPassword = authenticationHelper.getRandomPassword(); - - this.client.request('ConfirmDevice', { - DeviceKey: dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey, - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - DeviceSecretVerifierConfig: deviceSecretVerifierConfig, - DeviceName: navigator.userAgent, - }, (errConfirm, dataConfirm) => { - if (errConfirm) { - return callback.onFailure(errConfirm); - } - - this.deviceKey = dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey; - this.cacheDeviceKeyAndPassword(); - if (dataConfirm.UserConfirmationNecessary === true) { - return callback.onSuccess( - this.signInUserSession, - dataConfirm.UserConfirmationNecessary); - } - return callback.onSuccess(this.signInUserSession); - }); - return undefined; - }); - return undefined; - }); - } - - /** - * This is used by an authenticated user to change the current password - * @param {string} oldUserPassword The current password. - * @param {string} newUserPassword The requested new password. - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - changePassword(oldUserPassword, newUserPassword, callback) { - if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { - return callback(new Error('User is not authenticated'), null); - } - - this.client.request('ChangePassword', { - PreviousPassword: oldUserPassword, - ProposedPassword: newUserPassword, - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, err => { - if (err) { - return callback(err, null); - } - return callback(null, 'SUCCESS'); - }); - return undefined; - } - - /** - * This is used by an authenticated user to enable MFA for itself - * @deprecated - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - enableMFA(callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback(new Error('User is not authenticated'), null); - } - - const mfaOptions = []; - const mfaEnabled = { - DeliveryMedium: 'SMS', - AttributeName: 'phone_number', - }; - mfaOptions.push(mfaEnabled); - - this.client.request('SetUserSettings', { - MFAOptions: mfaOptions, - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, err => { - if (err) { - return callback(err, null); - } - return callback(null, 'SUCCESS'); - }); - return undefined; - } - - /** - * This is used by an authenticated user to enable MFA for itself - * @param {IMfaSettings} smsMfaSettings the sms mfa settings - * @param {IMFASettings} softwareTokenMfaSettings the software token mfa settings - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - setUserMfaPreference(smsMfaSettings, softwareTokenMfaSettings, callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback(new Error('User is not authenticated'), null); - } - - this.client.request('SetUserMFAPreference', { - SMSMfaSettings: smsMfaSettings, - SoftwareTokenMfaSettings: softwareTokenMfaSettings, - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, err => { - if (err) { - return callback(err, null); - } - return callback(null, 'SUCCESS'); - }); - return undefined; - } - - /** - * This is used by an authenticated user to disable MFA for itself - * @deprecated - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - disableMFA(callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback(new Error('User is not authenticated'), null); - } - - const mfaOptions = []; - - this.client.request('SetUserSettings', { - MFAOptions: mfaOptions, - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, err => { - if (err) { - return callback(err, null); - } - return callback(null, 'SUCCESS'); - }); - return undefined; - } - - - /** - * This is used by an authenticated user to delete itself - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - deleteUser(callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback(new Error('User is not authenticated'), null); - } - - this.client.request('DeleteUser', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, err => { - if (err) { - return callback(err, null); - } - this.clearCachedUser(); - return callback(null, 'SUCCESS'); - }); - return undefined; - } - - /** - * @typedef {CognitoUserAttribute | { Name:string, Value:string }} AttributeArg - */ - /** - * This is used by an authenticated user to change a list of attributes - * @param {AttributeArg[]} attributes A list of the new user attributes. - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - updateAttributes(attributes, callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback(new Error('User is not authenticated'), null); - } - - this.client.request('UpdateUserAttributes', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - UserAttributes: attributes, - }, err => { - if (err) { - return callback(err, null); - } - return callback(null, 'SUCCESS'); - }); - return undefined; - } - - /** - * This is used by an authenticated user to get a list of attributes - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - getUserAttributes(callback) { - if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { - return callback(new Error('User is not authenticated'), null); - } - - this.client.request('GetUser', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, (err, userData) => { - if (err) { - return callback(err, null); - } - - const attributeList = []; - - for (let i = 0; i < userData.UserAttributes.length; i++) { - const attribute = { - Name: userData.UserAttributes[i].Name, - Value: userData.UserAttributes[i].Value, - }; - const userAttribute = new CognitoUserAttribute(attribute); - attributeList.push(userAttribute); - } - - return callback(null, attributeList); - }); - return undefined; - } - - /** - * This is used by an authenticated user to get the MFAOptions - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - getMFAOptions(callback) { - if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { - return callback(new Error('User is not authenticated'), null); - } - - this.client.request('GetUser', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, (err, userData) => { - if (err) { - return callback(err, null); - } - - return callback(null, userData.MFAOptions); - }); - return undefined; - } - - /** - * This is used by an authenticated users to get the userData - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - getUserData(callback, params) { - if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { - this.clearCachedUserData(); - return callback(new Error('User is not authenticated'), null); - } - - const bypassCache = params ? params.bypassCache : false; - - const userData = this.storage.getItem(this.userDataKey); - // get the cached user data - - if (!userData || bypassCache) { - this.client.request('GetUser', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, (err, latestUserData) => { - if (err) { - return callback(err, null); - } - this.cacheUserData(latestUserData); - const refresh = this.signInUserSession.getRefreshToken(); - if (refresh && refresh.getToken()) { - this.refreshSession(refresh, (refreshError, data) => { - if (refreshError) { - return callback(refreshError, null); - } - return callback(null, latestUserData); - }); - } else { - return callback(null, latestUserData); - } - }); - } else { - try { - return callback(null, JSON.parse(userData)); - } catch (err) { - this.clearCachedUserData(); - return callback(err, null); - } - } - return undefined; - } - - /** - * This is used by an authenticated user to delete a list of attributes - * @param {string[]} attributeList Names of the attributes to delete. - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - deleteAttributes(attributeList, callback) { - if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { - return callback(new Error('User is not authenticated'), null); - } - - this.client.request('DeleteUserAttributes', { - UserAttributeNames: attributeList, - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, err => { - if (err) { - return callback(err, null); - } - return callback(null, 'SUCCESS'); - }); - return undefined; - } - - /** - * This is used by a user to resend a confirmation code - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - resendConfirmationCode(callback) { - const jsonReq = { - ClientId: this.pool.getClientId(), - Username: this.username, - }; - - this.client.request('ResendConfirmationCode', jsonReq, (err, result) => { - if (err) { - return callback(err, null); - } - return callback(null, result); - }); - } - - /** - * This is used to get a session, either from the session object - * or from the local storage, or by using a refresh token - * - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - getSession(callback) { - if (this.username == null) { - return callback(new Error('Username is null. Cannot retrieve a new session'), null); - } - - if (this.signInUserSession != null && this.signInUserSession.isValid()) { - return callback(null, this.signInUserSession); - } - - const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}.${this.username}`; - const idTokenKey = `${keyPrefix}.idToken`; - const accessTokenKey = `${keyPrefix}.accessToken`; - const refreshTokenKey = `${keyPrefix}.refreshToken`; - const clockDriftKey = `${keyPrefix}.clockDrift`; - - if (this.storage.getItem(idTokenKey)) { - const idToken = new CognitoIdToken({ - IdToken: this.storage.getItem(idTokenKey), - }); - const accessToken = new CognitoAccessToken({ - AccessToken: this.storage.getItem(accessTokenKey), - }); - const refreshToken = new CognitoRefreshToken({ - RefreshToken: this.storage.getItem(refreshTokenKey), - }); - const clockDrift = parseInt(this.storage.getItem(clockDriftKey), 0) || 0; - - const sessionData = { - IdToken: idToken, - AccessToken: accessToken, - RefreshToken: refreshToken, - ClockDrift: clockDrift, - }; - const cachedSession = new CognitoUserSession(sessionData); - if (cachedSession.isValid()) { - this.signInUserSession = cachedSession; - return callback(null, this.signInUserSession); - } - - if (!refreshToken.getToken()) { - return callback(new Error('Cannot retrieve a new session. Please authenticate.'), null); - } - - this.refreshSession(refreshToken, callback); - } else { - callback(new Error('Local storage is missing an ID Token, Please authenticate'), null); - } - - return undefined; - } - - - /** - * This uses the refreshToken to retrieve a new session - * @param {CognitoRefreshToken} refreshToken A previous session's refresh token. - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - refreshSession(refreshToken, callback) { - const authParameters = {}; - authParameters.REFRESH_TOKEN = refreshToken.getToken(); - const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}`; - const lastUserKey = `${keyPrefix}.LastAuthUser`; - - if (this.storage.getItem(lastUserKey)) { - this.username = this.storage.getItem(lastUserKey); - const deviceKeyKey = `${keyPrefix}.${this.username}.deviceKey`; - this.deviceKey = this.storage.getItem(deviceKeyKey); - authParameters.DEVICE_KEY = this.deviceKey; - } - - const jsonReq = { - ClientId: this.pool.getClientId(), - AuthFlow: 'REFRESH_TOKEN_AUTH', - AuthParameters: authParameters, - }; - if (this.getUserContextData()) { - jsonReq.UserContextData = this.getUserContextData(); - } - this.client.request('InitiateAuth', jsonReq, (err, authResult) => { - if (err) { - if (err.code === 'NotAuthorizedException') { - this.clearCachedUser(); - } - return callback(err, null); - } - if (authResult) { - const authenticationResult = authResult.AuthenticationResult; - if (!Object.prototype.hasOwnProperty.call(authenticationResult, 'RefreshToken')) { - authenticationResult.RefreshToken = refreshToken.getToken(); - } - this.signInUserSession = this.getCognitoUserSession(authenticationResult); - this.cacheTokens(); - return callback(null, this.signInUserSession); - } - return undefined; - }); - } - - /** - * This is used to save the session tokens to local storage - * @returns {void} - */ - cacheTokens() { - const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}`; - const idTokenKey = `${keyPrefix}.${this.username}.idToken`; - const accessTokenKey = `${keyPrefix}.${this.username}.accessToken`; - const refreshTokenKey = `${keyPrefix}.${this.username}.refreshToken`; - const clockDriftKey = `${keyPrefix}.${this.username}.clockDrift`; - const lastUserKey = `${keyPrefix}.LastAuthUser`; - - this.storage.setItem(idTokenKey, this.signInUserSession.getIdToken().getJwtToken()); - this.storage.setItem(accessTokenKey, this.signInUserSession.getAccessToken().getJwtToken()); - this.storage.setItem(refreshTokenKey, this.signInUserSession.getRefreshToken().getToken()); - this.storage.setItem(clockDriftKey, `${this.signInUserSession.getClockDrift()}`); - this.storage.setItem(lastUserKey, this.username); - } - - /** - * This is to cache user data - */ - cacheUserData(userData) { - this.storage.setItem(this.userDataKey, JSON.stringify(userData)); - } - - /** - * This is to remove cached user data - */ - clearCachedUserData() { - this.storage.removeItem(this.userDataKey); - } - - clearCachedUser() { - this.clearCachedTokens(); - this.clearCachedUserData(); - } - - /** - * This is used to cache the device key and device group and device password - * @returns {void} - */ - cacheDeviceKeyAndPassword() { - const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}.${this.username}`; - const deviceKeyKey = `${keyPrefix}.deviceKey`; - const randomPasswordKey = `${keyPrefix}.randomPasswordKey`; - const deviceGroupKeyKey = `${keyPrefix}.deviceGroupKey`; - - this.storage.setItem(deviceKeyKey, this.deviceKey); - this.storage.setItem(randomPasswordKey, this.randomPassword); - this.storage.setItem(deviceGroupKeyKey, this.deviceGroupKey); - } - - /** - * This is used to get current device key and device group and device password - * @returns {void} - */ - getCachedDeviceKeyAndPassword() { - const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}.${this.username}`; - const deviceKeyKey = `${keyPrefix}.deviceKey`; - const randomPasswordKey = `${keyPrefix}.randomPasswordKey`; - const deviceGroupKeyKey = `${keyPrefix}.deviceGroupKey`; - - if (this.storage.getItem(deviceKeyKey)) { - this.deviceKey = this.storage.getItem(deviceKeyKey); - this.randomPassword = this.storage.getItem(randomPasswordKey); - this.deviceGroupKey = this.storage.getItem(deviceGroupKeyKey); - } - } - - /** - * This is used to clear the device key info from local storage - * @returns {void} - */ - clearCachedDeviceKeyAndPassword() { - const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}.${this.username}`; - const deviceKeyKey = `${keyPrefix}.deviceKey`; - const randomPasswordKey = `${keyPrefix}.randomPasswordKey`; - const deviceGroupKeyKey = `${keyPrefix}.deviceGroupKey`; - - this.storage.removeItem(deviceKeyKey); - this.storage.removeItem(randomPasswordKey); - this.storage.removeItem(deviceGroupKeyKey); - } - - /** - * This is used to clear the session tokens from local storage - * @returns {void} - */ - clearCachedTokens() { - const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}`; - const idTokenKey = `${keyPrefix}.${this.username}.idToken`; - const accessTokenKey = `${keyPrefix}.${this.username}.accessToken`; - const refreshTokenKey = `${keyPrefix}.${this.username}.refreshToken`; - const lastUserKey = `${keyPrefix}.LastAuthUser`; - const clockDriftKey = `${keyPrefix}.${this.username}.clockDrift`; - - this.storage.removeItem(idTokenKey); - this.storage.removeItem(accessTokenKey); - this.storage.removeItem(refreshTokenKey); - this.storage.removeItem(lastUserKey); - this.storage.removeItem(clockDriftKey); - } - - /** - * This is used to build a user session from tokens retrieved in the authentication result - * @param {object} authResult Successful auth response from server. - * @returns {CognitoUserSession} The new user session. - * @private - */ - getCognitoUserSession(authResult) { - const idToken = new CognitoIdToken(authResult); - const accessToken = new CognitoAccessToken(authResult); - const refreshToken = new CognitoRefreshToken(authResult); - - const sessionData = { - IdToken: idToken, - AccessToken: accessToken, - RefreshToken: refreshToken, - }; - - return new CognitoUserSession(sessionData); - } - - /** - * This is used to initiate a forgot password request - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {inputVerificationCode?} callback.inputVerificationCode - * Optional callback raised instead of onSuccess with response data. - * @param {onSuccess} callback.onSuccess Called on success. - * @returns {void} - */ - forgotPassword(callback) { - const jsonReq = { - ClientId: this.pool.getClientId(), - Username: this.username, - }; - if (this.getUserContextData()) { - jsonReq.UserContextData = this.getUserContextData(); - } - this.client.request('ForgotPassword', jsonReq, (err, data) => { - if (err) { - return callback.onFailure(err); - } - if (typeof callback.inputVerificationCode === 'function') { - return callback.inputVerificationCode(data); - } - return callback.onSuccess(data); - }); - } - - /** - * This is used to confirm a new password using a confirmationCode - * @param {string} confirmationCode Code entered by user. - * @param {string} newPassword Confirm new password. - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {onSuccess} callback.onSuccess Called on success. - * @returns {void} - */ - confirmPassword(confirmationCode, newPassword, callback) { - const jsonReq = { - ClientId: this.pool.getClientId(), - Username: this.username, - ConfirmationCode: confirmationCode, - Password: newPassword, - }; - if (this.getUserContextData()) { - jsonReq.UserContextData = this.getUserContextData(); - } - this.client.request('ConfirmForgotPassword', jsonReq, err => { - if (err) { - return callback.onFailure(err); - } - return callback.onSuccess(); - }); - } - - /** - * This is used to initiate an attribute confirmation request - * @param {string} attributeName User attribute that needs confirmation. - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {inputVerificationCode} callback.inputVerificationCode Called on success. - * @returns {void} - */ - getAttributeVerificationCode(attributeName, callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback.onFailure(new Error('User is not authenticated')); - } - - this.client.request('GetUserAttributeVerificationCode', { - AttributeName: attributeName, - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, (err, data) => { - if (err) { - return callback.onFailure(err); - } - if (typeof callback.inputVerificationCode === 'function') { - return callback.inputVerificationCode(data); - } - return callback.onSuccess(); - }); - return undefined; - } - - /** - * This is used to confirm an attribute using a confirmation code - * @param {string} attributeName Attribute being confirmed. - * @param {string} confirmationCode Code entered by user. - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {onSuccess} callback.onSuccess Called on success. - * @returns {void} - */ - verifyAttribute(attributeName, confirmationCode, callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback.onFailure(new Error('User is not authenticated')); - } - - this.client.request('VerifyUserAttribute', { - AttributeName: attributeName, - Code: confirmationCode, - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, err => { - if (err) { - return callback.onFailure(err); - } - return callback.onSuccess('SUCCESS'); - }); - return undefined; - } - - /** - * This is used to get the device information using the current device key - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {onSuccess<*>} callback.onSuccess Called on success with device data. - * @returns {void} - */ - getDevice(callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback.onFailure(new Error('User is not authenticated')); - } - - this.client.request('GetDevice', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - DeviceKey: this.deviceKey, - }, (err, data) => { - if (err) { - return callback.onFailure(err); - } - return callback.onSuccess(data); - }); - return undefined; - } - - /** - * This is used to forget a specific device - * @param {string} deviceKey Device key. - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {onSuccess} callback.onSuccess Called on success. - * @returns {void} - */ - forgetSpecificDevice(deviceKey, callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback.onFailure(new Error('User is not authenticated')); - } - - this.client.request('ForgetDevice', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - DeviceKey: deviceKey, - }, err => { - if (err) { - return callback.onFailure(err); - } - return callback.onSuccess('SUCCESS'); - }); - return undefined; - } - - /** - * This is used to forget the current device - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {onSuccess} callback.onSuccess Called on success. - * @returns {void} - */ - forgetDevice(callback) { - this.forgetSpecificDevice(this.deviceKey, { - onFailure: callback.onFailure, - onSuccess: result => { - this.deviceKey = null; - this.deviceGroupKey = null; - this.randomPassword = null; - this.clearCachedDeviceKeyAndPassword(); - return callback.onSuccess(result); - }, - }); - } - - /** - * This is used to set the device status as remembered - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {onSuccess} callback.onSuccess Called on success. - * @returns {void} - */ - setDeviceStatusRemembered(callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback.onFailure(new Error('User is not authenticated')); - } - - this.client.request('UpdateDeviceStatus', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - DeviceKey: this.deviceKey, - DeviceRememberedStatus: 'remembered', - }, err => { - if (err) { - return callback.onFailure(err); - } - return callback.onSuccess('SUCCESS'); - }); - return undefined; - } - - /** - * This is used to set the device status as not remembered - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {onSuccess} callback.onSuccess Called on success. - * @returns {void} - */ - setDeviceStatusNotRemembered(callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback.onFailure(new Error('User is not authenticated')); - } - - this.client.request('UpdateDeviceStatus', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - DeviceKey: this.deviceKey, - DeviceRememberedStatus: 'not_remembered', - }, err => { - if (err) { - return callback.onFailure(err); - } - return callback.onSuccess('SUCCESS'); - }); - return undefined; - } - - /** - * This is used to list all devices for a user - * - * @param {int} limit the number of devices returned in a call - * @param {string} paginationToken the pagination token in case any was returned before - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {onSuccess<*>} callback.onSuccess Called on success with device list. - * @returns {void} - */ - listDevices(limit, paginationToken, callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback.onFailure(new Error('User is not authenticated')); - } - - this.client.request('ListDevices', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - Limit: limit, - PaginationToken: paginationToken, - }, (err, data) => { - if (err) { - return callback.onFailure(err); - } - return callback.onSuccess(data); - }); - return undefined; - } - - /** - * This is used to globally revoke all tokens issued to a user - * @param {object} callback Result callback map. - * @param {onFailure} callback.onFailure Called on any error. - * @param {onSuccess} callback.onSuccess Called on success. - * @returns {void} - */ - globalSignOut(callback) { - if (this.signInUserSession == null || !this.signInUserSession.isValid()) { - return callback.onFailure(new Error('User is not authenticated')); - } - - this.client.request('GlobalSignOut', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, err => { - if (err) { - return callback.onFailure(err); - } - this.clearCachedUser(); - return callback.onSuccess('SUCCESS'); - }); - return undefined; - } - - /** - * This is used for the user to signOut of the application and clear the cached tokens. - * @returns {void} - */ - signOut() { - this.signInUserSession = null; - this.clearCachedUser(); - } - - /** - * This is used by a user trying to select a given MFA - * @param {string} answerChallenge the mfa the user wants - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - sendMFASelectionAnswer(answerChallenge, callback) { - const challengeResponses = {}; - challengeResponses.USERNAME = this.username; - challengeResponses.ANSWER = answerChallenge; - - const jsonReq = { - ChallengeName: 'SELECT_MFA_TYPE', - ChallengeResponses: challengeResponses, - ClientId: this.pool.getClientId(), - Session: this.Session, - }; - if (this.getUserContextData()) { - jsonReq.UserContextData = this.getUserContextData(); - } - this.client.request('RespondToAuthChallenge', jsonReq, (err, data) => { - if (err) { - return callback.onFailure(err); - } - this.Session = data.Session; - if (answerChallenge === 'SMS_MFA') { - return callback.mfaRequired(data.challengeName, data.challengeParameters); - } - if (answerChallenge === 'SOFTWARE_TOKEN_MFA') { - return callback.totpRequired(data.challengeName, data.challengeParameters); - } - return undefined; - }); - } - - /** - * This returns the user context data for advanced security feature. - * @returns {void} - */ - getUserContextData() { - const pool = this.pool; - return pool.getUserContextData(this.username); - } - - /** - * This is used by an authenticated or a user trying to authenticate to associate a TOTP MFA - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - associateSoftwareToken(callback) { - if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { - this.client.request('AssociateSoftwareToken', { - Session: this.Session, - }, (err, data) => { - if (err) { - return callback.onFailure(err); - } - this.Session = data.Session; - return callback.associateSecretCode(data.SecretCode); - }); - } else { - this.client.request('AssociateSoftwareToken', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - }, (err, data) => { - if (err) { - return callback.onFailure(err); - } - return callback.associateSecretCode(data.SecretCode); - }); - } - } - - /** - * This is used by an authenticated or a user trying to authenticate to verify a TOTP MFA - * @param {string} totpCode The MFA code entered by the user. - * @param {string} friendlyDeviceName The device name we are assigning to the device. - * @param {nodeCallback} callback Called on success or error. - * @returns {void} - */ - verifySoftwareToken(totpCode, friendlyDeviceName, callback) { - if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { - this.client.request('VerifySoftwareToken', { - Session: this.Session, - UserCode: totpCode, - FriendlyDeviceName: friendlyDeviceName, - }, (err, data) => { - if (err) { - return callback.onFailure(err); - } - this.Session = data.Session; - const challengeResponses = {}; - challengeResponses.USERNAME = this.username; - const jsonReq = { - ChallengeName: 'MFA_SETUP', - ClientId: this.pool.getClientId(), - ChallengeResponses: challengeResponses, - Session: this.Session, - }; - if (this.getUserContextData()) { - jsonReq.UserContextData = this.getUserContextData(); - } - this.client.request('RespondToAuthChallenge', - jsonReq, (errRespond, dataRespond) => { - if (errRespond) { - return callback.onFailure(errRespond); - } - this.signInUserSession = this.getCognitoUserSession(dataRespond.AuthenticationResult); - this.cacheTokens(); - return callback.onSuccess(this.signInUserSession); - }); - return undefined; - }); - } else { - this.client.request('VerifySoftwareToken', { - AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), - UserCode: totpCode, - FriendlyDeviceName: friendlyDeviceName, - }, (err, data) => { - if (err) { - return callback.onFailure(err); - } - return callback.onSuccess(data); - }); - } - } + /** + * Constructs a new CognitoUser object + * @param {object} data Creation options + * @param {string} data.Username The user's username. + * @param {CognitoUserPool} data.Pool Pool containing the user. + * @param {object} data.Storage Optional storage object. + */ + constructor(data) { + if (data == null || data.Username == null || data.Pool == null) { + throw new Error('Username and pool information are required.'); + } + + this.username = data.Username || ''; + this.pool = data.Pool; + this.Session = null; + + this.client = data.Pool.client; + + this.signInUserSession = null; + this.authenticationFlowType = 'USER_SRP_AUTH'; + + this.storage = data.Storage || new StorageHelper().getStorage(); + + this.keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}`; + this.userDataKey = `${this.keyPrefix}.${this.username}.userData`; + } + + /** + * Sets the session for this user + * @param {CognitoUserSession} signInUserSession the session + * @returns {void} + */ + setSignInUserSession(signInUserSession) { + this.clearCachedUserData(); + this.signInUserSession = signInUserSession; + this.cacheTokens(); + } + + /** + * @returns {CognitoUserSession} the current session for this user + */ + getSignInUserSession() { + return this.signInUserSession; + } + + /** + * @returns {string} the user's username + */ + getUsername() { + return this.username; + } + + /** + * @returns {String} the authentication flow type + */ + getAuthenticationFlowType() { + return this.authenticationFlowType; + } + + /** + * sets authentication flow type + * @param {string} authenticationFlowType New value. + * @returns {void} + */ + setAuthenticationFlowType(authenticationFlowType) { + this.authenticationFlowType = authenticationFlowType; + } + + /** + * This is used for authenticating the user through the custom authentication flow. + * @param {AuthenticationDetails} authDetails Contains the authentication data + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {customChallenge} callback.customChallenge Custom challenge + * response required to continue. + * @param {authSuccess} callback.onSuccess Called on success with the new session. + * @returns {void} + */ + initiateAuth(authDetails, callback) { + const authParameters = authDetails.getAuthParameters(); + authParameters.USERNAME = this.username; + + const jsonReq = { + AuthFlow: 'CUSTOM_AUTH', + ClientId: this.pool.getClientId(), + AuthParameters: authParameters, + ClientMetadata: authDetails.getValidationData(), + }; + if (this.getUserContextData()) { + jsonReq.UserContextData = this.getUserContextData(); + } + + this.client.request('InitiateAuth', jsonReq, (err, data) => { + if (err) { + return callback.onFailure(err); + } + const challengeName = data.ChallengeName; + const challengeParameters = data.ChallengeParameters; + + if (challengeName === 'CUSTOM_CHALLENGE') { + this.Session = data.Session; + return callback.customChallenge(challengeParameters); + } + this.signInUserSession = this.getCognitoUserSession( + data.AuthenticationResult + ); + this.cacheTokens(); + return callback.onSuccess(this.signInUserSession); + }); + } + + /** + * This is used for authenticating the user. + * stuff + * @param {AuthenticationDetails} authDetails Contains the authentication data + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {newPasswordRequired} callback.newPasswordRequired new + * password and any required attributes are required to continue + * @param {mfaRequired} callback.mfaRequired MFA code + * required to continue. + * @param {customChallenge} callback.customChallenge Custom challenge + * response required to continue. + * @param {authSuccess} callback.onSuccess Called on success with the new session. + * @returns {void} + */ + authenticateUser(authDetails, callback) { + if (this.authenticationFlowType === 'USER_PASSWORD_AUTH') { + return this.authenticateUserPlainUsernamePassword(authDetails, callback); + } else if ( + this.authenticationFlowType === 'USER_SRP_AUTH' || + this.authenticationFlowType === 'CUSTOM_AUTH' + ) { + return this.authenticateUserDefaultAuth(authDetails, callback); + } + return callback.onFailure( + new Error('Authentication flow type is invalid.') + ); + } + + /** + * PRIVATE ONLY: This is an internal only method and should not + * be directly called by the consumers. + * It calls the AuthenticationHelper for SRP related + * stuff + * @param {AuthenticationDetails} authDetails Contains the authentication data + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {newPasswordRequired} callback.newPasswordRequired new + * password and any required attributes are required to continue + * @param {mfaRequired} callback.mfaRequired MFA code + * required to continue. + * @param {customChallenge} callback.customChallenge Custom challenge + * response required to continue. + * @param {authSuccess} callback.onSuccess Called on success with the new session. + * @returns {void} + */ + authenticateUserDefaultAuth(authDetails, callback) { + const authenticationHelper = new AuthenticationHelper( + this.pool.getUserPoolId().split('_')[1] + ); + const dateHelper = new DateHelper(); + + let serverBValue; + let salt; + const authParameters = {}; + + if (this.deviceKey != null) { + authParameters.DEVICE_KEY = this.deviceKey; + } + + authParameters.USERNAME = this.username; + authenticationHelper.getLargeAValue((errOnAValue, aValue) => { + // getLargeAValue callback start + if (errOnAValue) { + callback.onFailure(errOnAValue); + } + + authParameters.SRP_A = aValue.toString(16); + + if (this.authenticationFlowType === 'CUSTOM_AUTH') { + authParameters.CHALLENGE_NAME = 'SRP_A'; + } + + const jsonReq = { + AuthFlow: this.authenticationFlowType, + ClientId: this.pool.getClientId(), + AuthParameters: authParameters, + ClientMetadata: authDetails.getValidationData(), + }; + if (this.getUserContextData(this.username)) { + jsonReq.UserContextData = this.getUserContextData(this.username); + } + + this.client.request('InitiateAuth', jsonReq, (err, data) => { + if (err) { + return callback.onFailure(err); + } + + const challengeParameters = data.ChallengeParameters; + + this.username = challengeParameters.USER_ID_FOR_SRP; + serverBValue = new BigInteger(challengeParameters.SRP_B, 16); + salt = new BigInteger(challengeParameters.SALT, 16); + this.getCachedDeviceKeyAndPassword(); + + authenticationHelper.getPasswordAuthenticationKey( + this.username, + authDetails.getPassword(), + serverBValue, + salt, + (errOnHkdf, hkdf) => { + // getPasswordAuthenticationKey callback start + if (errOnHkdf) { + callback.onFailure(errOnHkdf); + } + + const dateNow = dateHelper.getNowString(); + + const message = CryptoJS.lib.WordArray.create( + Buffer.concat([ + Buffer.from(this.pool.getUserPoolId().split('_')[1], 'utf8'), + Buffer.from(this.username, 'utf8'), + Buffer.from(challengeParameters.SECRET_BLOCK, 'base64'), + Buffer.from(dateNow, 'utf8'), + ]) + ); + const key = CryptoJS.lib.WordArray.create(hkdf); + const signatureString = Base64.stringify(HmacSHA256(message, key)); + + const challengeResponses = {}; + + challengeResponses.USERNAME = this.username; + challengeResponses.PASSWORD_CLAIM_SECRET_BLOCK = + challengeParameters.SECRET_BLOCK; + challengeResponses.TIMESTAMP = dateNow; + challengeResponses.PASSWORD_CLAIM_SIGNATURE = signatureString; + + if (this.deviceKey != null) { + challengeResponses.DEVICE_KEY = this.deviceKey; + } + + const respondToAuthChallenge = (challenge, challengeCallback) => + this.client.request( + 'RespondToAuthChallenge', + challenge, + (errChallenge, dataChallenge) => { + if ( + errChallenge && + errChallenge.code === 'ResourceNotFoundException' && + errChallenge.message.toLowerCase().indexOf('device') !== -1 + ) { + challengeResponses.DEVICE_KEY = null; + this.deviceKey = null; + this.randomPassword = null; + this.deviceGroupKey = null; + this.clearCachedDeviceKeyAndPassword(); + return respondToAuthChallenge(challenge, challengeCallback); + } + return challengeCallback(errChallenge, dataChallenge); + } + ); + + const jsonReqResp = { + ChallengeName: 'PASSWORD_VERIFIER', + ClientId: this.pool.getClientId(), + ChallengeResponses: challengeResponses, + Session: data.Session, + }; + if (this.getUserContextData()) { + jsonReqResp.UserContextData = this.getUserContextData(); + } + respondToAuthChallenge( + jsonReqResp, + (errAuthenticate, dataAuthenticate) => { + if (errAuthenticate) { + return callback.onFailure(errAuthenticate); + } + + return this.authenticateUserInternal( + dataAuthenticate, + authenticationHelper, + callback + ); + } + ); + return undefined; + // getPasswordAuthenticationKey callback end + } + ); + return undefined; + }); + // getLargeAValue callback end + }); + } + + /** + * PRIVATE ONLY: This is an internal only method and should not + * be directly called by the consumers. + * @param {AuthenticationDetails} authDetails Contains the authentication data. + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {mfaRequired} callback.mfaRequired MFA code + * required to continue. + * @param {authSuccess} callback.onSuccess Called on success with the new session. + * @returns {void} + */ + authenticateUserPlainUsernamePassword(authDetails, callback) { + const authParameters = {}; + authParameters.USERNAME = this.username; + authParameters.PASSWORD = authDetails.getPassword(); + if (!authParameters.PASSWORD) { + callback.onFailure(new Error('PASSWORD parameter is required')); + return; + } + const authenticationHelper = new AuthenticationHelper( + this.pool.getUserPoolId().split('_')[1] + ); + this.getCachedDeviceKeyAndPassword(); + if (this.deviceKey != null) { + authParameters.DEVICE_KEY = this.deviceKey; + } + + const jsonReq = { + AuthFlow: 'USER_PASSWORD_AUTH', + ClientId: this.pool.getClientId(), + AuthParameters: authParameters, + ClientMetadata: authDetails.getValidationData(), + }; + if (this.getUserContextData(this.username)) { + jsonReq.UserContextData = this.getUserContextData(this.username); + } + // USER_PASSWORD_AUTH happens in a single round-trip: client sends userName and password, + // Cognito UserPools verifies password and returns tokens. + this.client.request('InitiateAuth', jsonReq, (err, authResult) => { + if (err) { + return callback.onFailure(err); + } + return this.authenticateUserInternal( + authResult, + authenticationHelper, + callback + ); + }); + } + + /** + * PRIVATE ONLY: This is an internal only method and should not + * be directly called by the consumers. + * @param {object} dataAuthenticate authentication data + * @param {object} authenticationHelper helper created + * @param {callback} callback passed on from caller + * @returns {void} + */ + authenticateUserInternal(dataAuthenticate, authenticationHelper, callback) { + const challengeName = dataAuthenticate.ChallengeName; + const challengeParameters = dataAuthenticate.ChallengeParameters; + + if (challengeName === 'SMS_MFA') { + this.Session = dataAuthenticate.Session; + return callback.mfaRequired(challengeName, challengeParameters); + } + + if (challengeName === 'SELECT_MFA_TYPE') { + this.Session = dataAuthenticate.Session; + return callback.selectMFAType(challengeName, challengeParameters); + } + + if (challengeName === 'MFA_SETUP') { + this.Session = dataAuthenticate.Session; + return callback.mfaSetup(challengeName, challengeParameters); + } + + if (challengeName === 'SOFTWARE_TOKEN_MFA') { + this.Session = dataAuthenticate.Session; + return callback.totpRequired(challengeName, challengeParameters); + } + + if (challengeName === 'CUSTOM_CHALLENGE') { + this.Session = dataAuthenticate.Session; + return callback.customChallenge(challengeParameters); + } + + if (challengeName === 'NEW_PASSWORD_REQUIRED') { + this.Session = dataAuthenticate.Session; + + let userAttributes = null; + let rawRequiredAttributes = null; + const requiredAttributes = []; + const userAttributesPrefix = authenticationHelper.getNewPasswordRequiredChallengeUserAttributePrefix(); + + if (challengeParameters) { + userAttributes = JSON.parse( + dataAuthenticate.ChallengeParameters.userAttributes + ); + rawRequiredAttributes = JSON.parse( + dataAuthenticate.ChallengeParameters.requiredAttributes + ); + } + + if (rawRequiredAttributes) { + for (let i = 0; i < rawRequiredAttributes.length; i++) { + requiredAttributes[i] = rawRequiredAttributes[i].substr( + userAttributesPrefix.length + ); + } + } + return callback.newPasswordRequired(userAttributes, requiredAttributes); + } + + if (challengeName === 'DEVICE_SRP_AUTH') { + this.getDeviceResponse(callback); + return undefined; + } + + this.signInUserSession = this.getCognitoUserSession( + dataAuthenticate.AuthenticationResult + ); + this.challengeName = challengeName; + this.cacheTokens(); + + const newDeviceMetadata = + dataAuthenticate.AuthenticationResult.NewDeviceMetadata; + if (newDeviceMetadata == null) { + return callback.onSuccess(this.signInUserSession); + } + + authenticationHelper.generateHashDevice( + dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceGroupKey, + dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey, + errGenHash => { + if (errGenHash) { + return callback.onFailure(errGenHash); + } + + const deviceSecretVerifierConfig = { + Salt: Buffer.from( + authenticationHelper.getSaltDevices(), + 'hex' + ).toString('base64'), + PasswordVerifier: Buffer.from( + authenticationHelper.getVerifierDevices(), + 'hex' + ).toString('base64'), + }; + + this.verifierDevices = deviceSecretVerifierConfig.PasswordVerifier; + this.deviceGroupKey = newDeviceMetadata.DeviceGroupKey; + this.randomPassword = authenticationHelper.getRandomPassword(); + + this.client.request( + 'ConfirmDevice', + { + DeviceKey: newDeviceMetadata.DeviceKey, + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + DeviceSecretVerifierConfig: deviceSecretVerifierConfig, + DeviceName: navigator.userAgent, + }, + (errConfirm, dataConfirm) => { + if (errConfirm) { + return callback.onFailure(errConfirm); + } + + this.deviceKey = + dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey; + this.cacheDeviceKeyAndPassword(); + if (dataConfirm.UserConfirmationNecessary === true) { + return callback.onSuccess( + this.signInUserSession, + dataConfirm.UserConfirmationNecessary + ); + } + return callback.onSuccess(this.signInUserSession); + } + ); + return undefined; + } + ); + return undefined; + } + + /** + * This method is user to complete the NEW_PASSWORD_REQUIRED challenge. + * Pass the new password with any new user attributes to be updated. + * User attribute keys must be of format userAttributes.. + * @param {string} newPassword new password for this user + * @param {object} requiredAttributeData map with values for all required attributes + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {mfaRequired} callback.mfaRequired MFA code required to continue. + * @param {customChallenge} callback.customChallenge Custom challenge + * response required to continue. + * @param {authSuccess} callback.onSuccess Called on success with the new session. + * @returns {void} + */ + completeNewPasswordChallenge(newPassword, requiredAttributeData, callback) { + if (!newPassword) { + return callback.onFailure(new Error('New password is required.')); + } + const authenticationHelper = new AuthenticationHelper( + this.pool.getUserPoolId().split('_')[1] + ); + const userAttributesPrefix = authenticationHelper.getNewPasswordRequiredChallengeUserAttributePrefix(); + + const finalUserAttributes = {}; + if (requiredAttributeData) { + Object.keys(requiredAttributeData).forEach(key => { + finalUserAttributes[userAttributesPrefix + key] = + requiredAttributeData[key]; + }); + } + + finalUserAttributes.NEW_PASSWORD = newPassword; + finalUserAttributes.USERNAME = this.username; + const jsonReq = { + ChallengeName: 'NEW_PASSWORD_REQUIRED', + ClientId: this.pool.getClientId(), + ChallengeResponses: finalUserAttributes, + Session: this.Session, + }; + if (this.getUserContextData()) { + jsonReq.UserContextData = this.getUserContextData(); + } + + this.client.request( + 'RespondToAuthChallenge', + jsonReq, + (errAuthenticate, dataAuthenticate) => { + if (errAuthenticate) { + return callback.onFailure(errAuthenticate); + } + return this.authenticateUserInternal( + dataAuthenticate, + authenticationHelper, + callback + ); + } + ); + return undefined; + } + + /** + * This is used to get a session using device authentication. It is called at the end of user + * authentication + * + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {authSuccess} callback.onSuccess Called on success with the new session. + * @returns {void} + * @private + */ + getDeviceResponse(callback) { + const authenticationHelper = new AuthenticationHelper(this.deviceGroupKey); + const dateHelper = new DateHelper(); + + const authParameters = {}; + + authParameters.USERNAME = this.username; + authParameters.DEVICE_KEY = this.deviceKey; + authenticationHelper.getLargeAValue((errAValue, aValue) => { + // getLargeAValue callback start + if (errAValue) { + callback.onFailure(errAValue); + } + + authParameters.SRP_A = aValue.toString(16); + + const jsonReq = { + ChallengeName: 'DEVICE_SRP_AUTH', + ClientId: this.pool.getClientId(), + ChallengeResponses: authParameters, + }; + if (this.getUserContextData()) { + jsonReq.UserContextData = this.getUserContextData(); + } + this.client.request('RespondToAuthChallenge', jsonReq, (err, data) => { + if (err) { + return callback.onFailure(err); + } + + const challengeParameters = data.ChallengeParameters; + + const serverBValue = new BigInteger(challengeParameters.SRP_B, 16); + const salt = new BigInteger(challengeParameters.SALT, 16); + + authenticationHelper.getPasswordAuthenticationKey( + this.deviceKey, + this.randomPassword, + serverBValue, + salt, + (errHkdf, hkdf) => { + // getPasswordAuthenticationKey callback start + if (errHkdf) { + return callback.onFailure(errHkdf); + } + + const dateNow = dateHelper.getNowString(); + + const message = CryptoJS.lib.WordArray.create( + Buffer.concat([ + Buffer.from(this.deviceGroupKey, 'utf8'), + Buffer.from(this.deviceKey, 'utf8'), + Buffer.from(challengeParameters.SECRET_BLOCK, 'base64'), + Buffer.from(dateNow, 'utf8'), + ]) + ); + const key = CryptoJS.lib.WordArray.create(hkdf); + const signatureString = Base64.stringify(HmacSHA256(message, key)); + + const challengeResponses = {}; + + challengeResponses.USERNAME = this.username; + challengeResponses.PASSWORD_CLAIM_SECRET_BLOCK = + challengeParameters.SECRET_BLOCK; + challengeResponses.TIMESTAMP = dateNow; + challengeResponses.PASSWORD_CLAIM_SIGNATURE = signatureString; + challengeResponses.DEVICE_KEY = this.deviceKey; + + const jsonReqResp = { + ChallengeName: 'DEVICE_PASSWORD_VERIFIER', + ClientId: this.pool.getClientId(), + ChallengeResponses: challengeResponses, + Session: data.Session, + }; + if (this.getUserContextData()) { + jsonReqResp.UserContextData = this.getUserContextData(); + } + + this.client.request( + 'RespondToAuthChallenge', + jsonReqResp, + (errAuthenticate, dataAuthenticate) => { + if (errAuthenticate) { + return callback.onFailure(errAuthenticate); + } + + this.signInUserSession = this.getCognitoUserSession( + dataAuthenticate.AuthenticationResult + ); + this.cacheTokens(); + + return callback.onSuccess(this.signInUserSession); + } + ); + return undefined; + // getPasswordAuthenticationKey callback end + } + ); + return undefined; + }); + // getLargeAValue callback end + }); + } + + /** + * This is used for a certain user to confirm the registration by using a confirmation code + * @param {string} confirmationCode Code entered by user. + * @param {bool} forceAliasCreation Allow migrating from an existing email / phone number. + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + confirmRegistration(confirmationCode, forceAliasCreation, callback) { + const jsonReq = { + ClientId: this.pool.getClientId(), + ConfirmationCode: confirmationCode, + Username: this.username, + ForceAliasCreation: forceAliasCreation, + }; + if (this.getUserContextData()) { + jsonReq.UserContextData = this.getUserContextData(); + } + this.client.request('ConfirmSignUp', jsonReq, err => { + if (err) { + return callback(err, null); + } + return callback(null, 'SUCCESS'); + }); + } + + /** + * This is used by the user once he has the responses to a custom challenge + * @param {string} answerChallenge The custom challenge answer. + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {customChallenge} callback.customChallenge + * Custom challenge response required to continue. + * @param {authSuccess} callback.onSuccess Called on success with the new session. + * @returns {void} + */ + sendCustomChallengeAnswer(answerChallenge, callback) { + const challengeResponses = {}; + challengeResponses.USERNAME = this.username; + challengeResponses.ANSWER = answerChallenge; + + const authenticationHelper = new AuthenticationHelper( + this.pool.getUserPoolId().split('_')[1] + ); + this.getCachedDeviceKeyAndPassword(); + if (this.deviceKey != null) { + challengeResponses.DEVICE_KEY = this.deviceKey; + } + + const jsonReq = { + ChallengeName: 'CUSTOM_CHALLENGE', + ChallengeResponses: challengeResponses, + ClientId: this.pool.getClientId(), + Session: this.Session, + }; + if (this.getUserContextData()) { + jsonReq.UserContextData = this.getUserContextData(); + } + this.client.request('RespondToAuthChallenge', jsonReq, (err, data) => { + if (err) { + return callback.onFailure(err); + } + + return this.authenticateUserInternal( + data, + authenticationHelper, + callback + ); + }); + } + + /** + * This is used by the user once he has an MFA code + * @param {string} confirmationCode The MFA code entered by the user. + * @param {object} callback Result callback map. + * @param {string} mfaType The mfa we are replying to. + * @param {onFailure} callback.onFailure Called on any error. + * @param {authSuccess} callback.onSuccess Called on success with the new session. + * @returns {void} + */ + sendMFACode(confirmationCode, callback, mfaType) { + const challengeResponses = {}; + challengeResponses.USERNAME = this.username; + challengeResponses.SMS_MFA_CODE = confirmationCode; + const mfaTypeSelection = mfaType || 'SMS_MFA'; + if (mfaTypeSelection === 'SOFTWARE_TOKEN_MFA') { + challengeResponses.SOFTWARE_TOKEN_MFA_CODE = confirmationCode; + } + + if (this.deviceKey != null) { + challengeResponses.DEVICE_KEY = this.deviceKey; + } + + const jsonReq = { + ChallengeName: mfaTypeSelection, + ChallengeResponses: challengeResponses, + ClientId: this.pool.getClientId(), + Session: this.Session, + }; + if (this.getUserContextData()) { + jsonReq.UserContextData = this.getUserContextData(); + } + + this.client.request( + 'RespondToAuthChallenge', + jsonReq, + (err, dataAuthenticate) => { + if (err) { + return callback.onFailure(err); + } + + const challengeName = dataAuthenticate.ChallengeName; + + if (challengeName === 'DEVICE_SRP_AUTH') { + this.getDeviceResponse(callback); + return undefined; + } + + this.signInUserSession = this.getCognitoUserSession( + dataAuthenticate.AuthenticationResult + ); + this.cacheTokens(); + + if (dataAuthenticate.AuthenticationResult.NewDeviceMetadata == null) { + return callback.onSuccess(this.signInUserSession); + } + + const authenticationHelper = new AuthenticationHelper( + this.pool.getUserPoolId().split('_')[1] + ); + authenticationHelper.generateHashDevice( + dataAuthenticate.AuthenticationResult.NewDeviceMetadata + .DeviceGroupKey, + dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey, + errGenHash => { + if (errGenHash) { + return callback.onFailure(errGenHash); + } + + const deviceSecretVerifierConfig = { + Salt: Buffer.from( + authenticationHelper.getSaltDevices(), + 'hex' + ).toString('base64'), + PasswordVerifier: Buffer.from( + authenticationHelper.getVerifierDevices(), + 'hex' + ).toString('base64'), + }; + + this.verifierDevices = deviceSecretVerifierConfig.PasswordVerifier; + this.deviceGroupKey = + dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceGroupKey; + this.randomPassword = authenticationHelper.getRandomPassword(); + + this.client.request( + 'ConfirmDevice', + { + DeviceKey: + dataAuthenticate.AuthenticationResult.NewDeviceMetadata + .DeviceKey, + AccessToken: this.signInUserSession + .getAccessToken() + .getJwtToken(), + DeviceSecretVerifierConfig: deviceSecretVerifierConfig, + DeviceName: navigator.userAgent, + }, + (errConfirm, dataConfirm) => { + if (errConfirm) { + return callback.onFailure(errConfirm); + } + + this.deviceKey = + dataAuthenticate.AuthenticationResult.NewDeviceMetadata.DeviceKey; + this.cacheDeviceKeyAndPassword(); + if (dataConfirm.UserConfirmationNecessary === true) { + return callback.onSuccess( + this.signInUserSession, + dataConfirm.UserConfirmationNecessary + ); + } + return callback.onSuccess(this.signInUserSession); + } + ); + return undefined; + } + ); + return undefined; + } + ); + } + + /** + * This is used by an authenticated user to change the current password + * @param {string} oldUserPassword The current password. + * @param {string} newUserPassword The requested new password. + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + changePassword(oldUserPassword, newUserPassword, callback) { + if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { + return callback(new Error('User is not authenticated'), null); + } + + this.client.request( + 'ChangePassword', + { + PreviousPassword: oldUserPassword, + ProposedPassword: newUserPassword, + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + err => { + if (err) { + return callback(err, null); + } + return callback(null, 'SUCCESS'); + } + ); + return undefined; + } + + /** + * This is used by an authenticated user to enable MFA for itself + * @deprecated + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + enableMFA(callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback(new Error('User is not authenticated'), null); + } + + const mfaOptions = []; + const mfaEnabled = { + DeliveryMedium: 'SMS', + AttributeName: 'phone_number', + }; + mfaOptions.push(mfaEnabled); + + this.client.request( + 'SetUserSettings', + { + MFAOptions: mfaOptions, + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + err => { + if (err) { + return callback(err, null); + } + return callback(null, 'SUCCESS'); + } + ); + return undefined; + } + + /** + * This is used by an authenticated user to enable MFA for itself + * @param {IMfaSettings} smsMfaSettings the sms mfa settings + * @param {IMFASettings} softwareTokenMfaSettings the software token mfa settings + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + setUserMfaPreference(smsMfaSettings, softwareTokenMfaSettings, callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback(new Error('User is not authenticated'), null); + } + + this.client.request( + 'SetUserMFAPreference', + { + SMSMfaSettings: smsMfaSettings, + SoftwareTokenMfaSettings: softwareTokenMfaSettings, + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + err => { + if (err) { + return callback(err, null); + } + return callback(null, 'SUCCESS'); + } + ); + return undefined; + } + + /** + * This is used by an authenticated user to disable MFA for itself + * @deprecated + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + disableMFA(callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback(new Error('User is not authenticated'), null); + } + + const mfaOptions = []; + + this.client.request( + 'SetUserSettings', + { + MFAOptions: mfaOptions, + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + err => { + if (err) { + return callback(err, null); + } + return callback(null, 'SUCCESS'); + } + ); + return undefined; + } + + /** + * This is used by an authenticated user to delete itself + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + deleteUser(callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback(new Error('User is not authenticated'), null); + } + + this.client.request( + 'DeleteUser', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + err => { + if (err) { + return callback(err, null); + } + this.clearCachedUser(); + return callback(null, 'SUCCESS'); + } + ); + return undefined; + } + + /** + * @typedef {CognitoUserAttribute | { Name:string, Value:string }} AttributeArg + */ + /** + * This is used by an authenticated user to change a list of attributes + * @param {AttributeArg[]} attributes A list of the new user attributes. + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + updateAttributes(attributes, callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback(new Error('User is not authenticated'), null); + } + + this.client.request( + 'UpdateUserAttributes', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + UserAttributes: attributes, + }, + err => { + if (err) { + return callback(err, null); + } + return callback(null, 'SUCCESS'); + } + ); + return undefined; + } + + /** + * This is used by an authenticated user to get a list of attributes + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + getUserAttributes(callback) { + if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { + return callback(new Error('User is not authenticated'), null); + } + + this.client.request( + 'GetUser', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + (err, userData) => { + if (err) { + return callback(err, null); + } + + const attributeList = []; + + for (let i = 0; i < userData.UserAttributes.length; i++) { + const attribute = { + Name: userData.UserAttributes[i].Name, + Value: userData.UserAttributes[i].Value, + }; + const userAttribute = new CognitoUserAttribute(attribute); + attributeList.push(userAttribute); + } + + return callback(null, attributeList); + } + ); + return undefined; + } + + /** + * This is used by an authenticated user to get the MFAOptions + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + getMFAOptions(callback) { + if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { + return callback(new Error('User is not authenticated'), null); + } + + this.client.request( + 'GetUser', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + (err, userData) => { + if (err) { + return callback(err, null); + } + + return callback(null, userData.MFAOptions); + } + ); + return undefined; + } + + /** + * This is used by an authenticated users to get the userData + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + getUserData(callback, params) { + if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { + this.clearCachedUserData(); + return callback(new Error('User is not authenticated'), null); + } + + const bypassCache = params ? params.bypassCache : false; + + const userData = this.storage.getItem(this.userDataKey); + // get the cached user data + + if (!userData || bypassCache) { + this.client.request( + 'GetUser', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + (err, latestUserData) => { + if (err) { + return callback(err, null); + } + this.cacheUserData(latestUserData); + const refresh = this.signInUserSession.getRefreshToken(); + if (refresh && refresh.getToken()) { + this.refreshSession(refresh, (refreshError, data) => { + if (refreshError) { + return callback(refreshError, null); + } + return callback(null, latestUserData); + }); + } else { + return callback(null, latestUserData); + } + } + ); + } else { + try { + return callback(null, JSON.parse(userData)); + } catch (err) { + this.clearCachedUserData(); + return callback(err, null); + } + } + return undefined; + } + + /** + * This is used by an authenticated user to delete a list of attributes + * @param {string[]} attributeList Names of the attributes to delete. + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + deleteAttributes(attributeList, callback) { + if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { + return callback(new Error('User is not authenticated'), null); + } + + this.client.request( + 'DeleteUserAttributes', + { + UserAttributeNames: attributeList, + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + err => { + if (err) { + return callback(err, null); + } + return callback(null, 'SUCCESS'); + } + ); + return undefined; + } + + /** + * This is used by a user to resend a confirmation code + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + resendConfirmationCode(callback) { + const jsonReq = { + ClientId: this.pool.getClientId(), + Username: this.username, + }; + + this.client.request('ResendConfirmationCode', jsonReq, (err, result) => { + if (err) { + return callback(err, null); + } + return callback(null, result); + }); + } + + /** + * This is used to get a session, either from the session object + * or from the local storage, or by using a refresh token + * + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + getSession(callback) { + if (this.username == null) { + return callback( + new Error('Username is null. Cannot retrieve a new session'), + null + ); + } + + if (this.signInUserSession != null && this.signInUserSession.isValid()) { + return callback(null, this.signInUserSession); + } + + const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}.${ + this.username + }`; + const idTokenKey = `${keyPrefix}.idToken`; + const accessTokenKey = `${keyPrefix}.accessToken`; + const refreshTokenKey = `${keyPrefix}.refreshToken`; + const clockDriftKey = `${keyPrefix}.clockDrift`; + + if (this.storage.getItem(idTokenKey)) { + const idToken = new CognitoIdToken({ + IdToken: this.storage.getItem(idTokenKey), + }); + const accessToken = new CognitoAccessToken({ + AccessToken: this.storage.getItem(accessTokenKey), + }); + const refreshToken = new CognitoRefreshToken({ + RefreshToken: this.storage.getItem(refreshTokenKey), + }); + const clockDrift = parseInt(this.storage.getItem(clockDriftKey), 0) || 0; + + const sessionData = { + IdToken: idToken, + AccessToken: accessToken, + RefreshToken: refreshToken, + ClockDrift: clockDrift, + }; + const cachedSession = new CognitoUserSession(sessionData); + if (cachedSession.isValid()) { + this.signInUserSession = cachedSession; + return callback(null, this.signInUserSession); + } + + if (!refreshToken.getToken()) { + return callback( + new Error('Cannot retrieve a new session. Please authenticate.'), + null + ); + } + + this.refreshSession(refreshToken, callback); + } else { + callback( + new Error('Local storage is missing an ID Token, Please authenticate'), + null + ); + } + + return undefined; + } + + /** + * This uses the refreshToken to retrieve a new session + * @param {CognitoRefreshToken} refreshToken A previous session's refresh token. + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + refreshSession(refreshToken, callback) { + const authParameters = {}; + authParameters.REFRESH_TOKEN = refreshToken.getToken(); + const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}`; + const lastUserKey = `${keyPrefix}.LastAuthUser`; + + if (this.storage.getItem(lastUserKey)) { + this.username = this.storage.getItem(lastUserKey); + const deviceKeyKey = `${keyPrefix}.${this.username}.deviceKey`; + this.deviceKey = this.storage.getItem(deviceKeyKey); + authParameters.DEVICE_KEY = this.deviceKey; + } + + const jsonReq = { + ClientId: this.pool.getClientId(), + AuthFlow: 'REFRESH_TOKEN_AUTH', + AuthParameters: authParameters, + }; + if (this.getUserContextData()) { + jsonReq.UserContextData = this.getUserContextData(); + } + this.client.request('InitiateAuth', jsonReq, (err, authResult) => { + if (err) { + if (err.code === 'NotAuthorizedException') { + this.clearCachedUser(); + } + return callback(err, null); + } + if (authResult) { + const authenticationResult = authResult.AuthenticationResult; + if ( + !Object.prototype.hasOwnProperty.call( + authenticationResult, + 'RefreshToken' + ) + ) { + authenticationResult.RefreshToken = refreshToken.getToken(); + } + this.signInUserSession = this.getCognitoUserSession( + authenticationResult + ); + this.cacheTokens(); + return callback(null, this.signInUserSession); + } + return undefined; + }); + } + + /** + * This is used to save the session tokens to local storage + * @returns {void} + */ + cacheTokens() { + const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}`; + const idTokenKey = `${keyPrefix}.${this.username}.idToken`; + const accessTokenKey = `${keyPrefix}.${this.username}.accessToken`; + const refreshTokenKey = `${keyPrefix}.${this.username}.refreshToken`; + const clockDriftKey = `${keyPrefix}.${this.username}.clockDrift`; + const lastUserKey = `${keyPrefix}.LastAuthUser`; + + this.storage.setItem( + idTokenKey, + this.signInUserSession.getIdToken().getJwtToken() + ); + this.storage.setItem( + accessTokenKey, + this.signInUserSession.getAccessToken().getJwtToken() + ); + this.storage.setItem( + refreshTokenKey, + this.signInUserSession.getRefreshToken().getToken() + ); + this.storage.setItem( + clockDriftKey, + `${this.signInUserSession.getClockDrift()}` + ); + this.storage.setItem(lastUserKey, this.username); + } + + /** + * This is to cache user data + */ + cacheUserData(userData) { + this.storage.setItem(this.userDataKey, JSON.stringify(userData)); + } + + /** + * This is to remove cached user data + */ + clearCachedUserData() { + this.storage.removeItem(this.userDataKey); + } + + clearCachedUser() { + this.clearCachedTokens(); + this.clearCachedUserData(); + } + + /** + * This is used to cache the device key and device group and device password + * @returns {void} + */ + cacheDeviceKeyAndPassword() { + const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}.${ + this.username + }`; + const deviceKeyKey = `${keyPrefix}.deviceKey`; + const randomPasswordKey = `${keyPrefix}.randomPasswordKey`; + const deviceGroupKeyKey = `${keyPrefix}.deviceGroupKey`; + + this.storage.setItem(deviceKeyKey, this.deviceKey); + this.storage.setItem(randomPasswordKey, this.randomPassword); + this.storage.setItem(deviceGroupKeyKey, this.deviceGroupKey); + } + + /** + * This is used to get current device key and device group and device password + * @returns {void} + */ + getCachedDeviceKeyAndPassword() { + const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}.${ + this.username + }`; + const deviceKeyKey = `${keyPrefix}.deviceKey`; + const randomPasswordKey = `${keyPrefix}.randomPasswordKey`; + const deviceGroupKeyKey = `${keyPrefix}.deviceGroupKey`; + + if (this.storage.getItem(deviceKeyKey)) { + this.deviceKey = this.storage.getItem(deviceKeyKey); + this.randomPassword = this.storage.getItem(randomPasswordKey); + this.deviceGroupKey = this.storage.getItem(deviceGroupKeyKey); + } + } + + /** + * This is used to clear the device key info from local storage + * @returns {void} + */ + clearCachedDeviceKeyAndPassword() { + const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}.${ + this.username + }`; + const deviceKeyKey = `${keyPrefix}.deviceKey`; + const randomPasswordKey = `${keyPrefix}.randomPasswordKey`; + const deviceGroupKeyKey = `${keyPrefix}.deviceGroupKey`; + + this.storage.removeItem(deviceKeyKey); + this.storage.removeItem(randomPasswordKey); + this.storage.removeItem(deviceGroupKeyKey); + } + + /** + * This is used to clear the session tokens from local storage + * @returns {void} + */ + clearCachedTokens() { + const keyPrefix = `CognitoIdentityServiceProvider.${this.pool.getClientId()}`; + const idTokenKey = `${keyPrefix}.${this.username}.idToken`; + const accessTokenKey = `${keyPrefix}.${this.username}.accessToken`; + const refreshTokenKey = `${keyPrefix}.${this.username}.refreshToken`; + const lastUserKey = `${keyPrefix}.LastAuthUser`; + const clockDriftKey = `${keyPrefix}.${this.username}.clockDrift`; + + this.storage.removeItem(idTokenKey); + this.storage.removeItem(accessTokenKey); + this.storage.removeItem(refreshTokenKey); + this.storage.removeItem(lastUserKey); + this.storage.removeItem(clockDriftKey); + } + + /** + * This is used to build a user session from tokens retrieved in the authentication result + * @param {object} authResult Successful auth response from server. + * @returns {CognitoUserSession} The new user session. + * @private + */ + getCognitoUserSession(authResult) { + const idToken = new CognitoIdToken(authResult); + const accessToken = new CognitoAccessToken(authResult); + const refreshToken = new CognitoRefreshToken(authResult); + + const sessionData = { + IdToken: idToken, + AccessToken: accessToken, + RefreshToken: refreshToken, + }; + + return new CognitoUserSession(sessionData); + } + + /** + * This is used to initiate a forgot password request + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {inputVerificationCode?} callback.inputVerificationCode + * Optional callback raised instead of onSuccess with response data. + * @param {onSuccess} callback.onSuccess Called on success. + * @returns {void} + */ + forgotPassword(callback) { + const jsonReq = { + ClientId: this.pool.getClientId(), + Username: this.username, + }; + if (this.getUserContextData()) { + jsonReq.UserContextData = this.getUserContextData(); + } + this.client.request('ForgotPassword', jsonReq, (err, data) => { + if (err) { + return callback.onFailure(err); + } + if (typeof callback.inputVerificationCode === 'function') { + return callback.inputVerificationCode(data); + } + return callback.onSuccess(data); + }); + } + + /** + * This is used to confirm a new password using a confirmationCode + * @param {string} confirmationCode Code entered by user. + * @param {string} newPassword Confirm new password. + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {onSuccess} callback.onSuccess Called on success. + * @returns {void} + */ + confirmPassword(confirmationCode, newPassword, callback) { + const jsonReq = { + ClientId: this.pool.getClientId(), + Username: this.username, + ConfirmationCode: confirmationCode, + Password: newPassword, + }; + if (this.getUserContextData()) { + jsonReq.UserContextData = this.getUserContextData(); + } + this.client.request('ConfirmForgotPassword', jsonReq, err => { + if (err) { + return callback.onFailure(err); + } + return callback.onSuccess(); + }); + } + + /** + * This is used to initiate an attribute confirmation request + * @param {string} attributeName User attribute that needs confirmation. + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {inputVerificationCode} callback.inputVerificationCode Called on success. + * @returns {void} + */ + getAttributeVerificationCode(attributeName, callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback.onFailure(new Error('User is not authenticated')); + } + + this.client.request( + 'GetUserAttributeVerificationCode', + { + AttributeName: attributeName, + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + (err, data) => { + if (err) { + return callback.onFailure(err); + } + if (typeof callback.inputVerificationCode === 'function') { + return callback.inputVerificationCode(data); + } + return callback.onSuccess(); + } + ); + return undefined; + } + + /** + * This is used to confirm an attribute using a confirmation code + * @param {string} attributeName Attribute being confirmed. + * @param {string} confirmationCode Code entered by user. + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {onSuccess} callback.onSuccess Called on success. + * @returns {void} + */ + verifyAttribute(attributeName, confirmationCode, callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback.onFailure(new Error('User is not authenticated')); + } + + this.client.request( + 'VerifyUserAttribute', + { + AttributeName: attributeName, + Code: confirmationCode, + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + err => { + if (err) { + return callback.onFailure(err); + } + return callback.onSuccess('SUCCESS'); + } + ); + return undefined; + } + + /** + * This is used to get the device information using the current device key + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {onSuccess<*>} callback.onSuccess Called on success with device data. + * @returns {void} + */ + getDevice(callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback.onFailure(new Error('User is not authenticated')); + } + + this.client.request( + 'GetDevice', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + DeviceKey: this.deviceKey, + }, + (err, data) => { + if (err) { + return callback.onFailure(err); + } + return callback.onSuccess(data); + } + ); + return undefined; + } + + /** + * This is used to forget a specific device + * @param {string} deviceKey Device key. + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {onSuccess} callback.onSuccess Called on success. + * @returns {void} + */ + forgetSpecificDevice(deviceKey, callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback.onFailure(new Error('User is not authenticated')); + } + + this.client.request( + 'ForgetDevice', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + DeviceKey: deviceKey, + }, + err => { + if (err) { + return callback.onFailure(err); + } + return callback.onSuccess('SUCCESS'); + } + ); + return undefined; + } + + /** + * This is used to forget the current device + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {onSuccess} callback.onSuccess Called on success. + * @returns {void} + */ + forgetDevice(callback) { + this.forgetSpecificDevice(this.deviceKey, { + onFailure: callback.onFailure, + onSuccess: result => { + this.deviceKey = null; + this.deviceGroupKey = null; + this.randomPassword = null; + this.clearCachedDeviceKeyAndPassword(); + return callback.onSuccess(result); + }, + }); + } + + /** + * This is used to set the device status as remembered + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {onSuccess} callback.onSuccess Called on success. + * @returns {void} + */ + setDeviceStatusRemembered(callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback.onFailure(new Error('User is not authenticated')); + } + + this.client.request( + 'UpdateDeviceStatus', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + DeviceKey: this.deviceKey, + DeviceRememberedStatus: 'remembered', + }, + err => { + if (err) { + return callback.onFailure(err); + } + return callback.onSuccess('SUCCESS'); + } + ); + return undefined; + } + + /** + * This is used to set the device status as not remembered + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {onSuccess} callback.onSuccess Called on success. + * @returns {void} + */ + setDeviceStatusNotRemembered(callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback.onFailure(new Error('User is not authenticated')); + } + + this.client.request( + 'UpdateDeviceStatus', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + DeviceKey: this.deviceKey, + DeviceRememberedStatus: 'not_remembered', + }, + err => { + if (err) { + return callback.onFailure(err); + } + return callback.onSuccess('SUCCESS'); + } + ); + return undefined; + } + + /** + * This is used to list all devices for a user + * + * @param {int} limit the number of devices returned in a call + * @param {string} paginationToken the pagination token in case any was returned before + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {onSuccess<*>} callback.onSuccess Called on success with device list. + * @returns {void} + */ + listDevices(limit, paginationToken, callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback.onFailure(new Error('User is not authenticated')); + } + + this.client.request( + 'ListDevices', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + Limit: limit, + PaginationToken: paginationToken, + }, + (err, data) => { + if (err) { + return callback.onFailure(err); + } + return callback.onSuccess(data); + } + ); + return undefined; + } + + /** + * This is used to globally revoke all tokens issued to a user + * @param {object} callback Result callback map. + * @param {onFailure} callback.onFailure Called on any error. + * @param {onSuccess} callback.onSuccess Called on success. + * @returns {void} + */ + globalSignOut(callback) { + if (this.signInUserSession == null || !this.signInUserSession.isValid()) { + return callback.onFailure(new Error('User is not authenticated')); + } + + this.client.request( + 'GlobalSignOut', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + err => { + if (err) { + return callback.onFailure(err); + } + this.clearCachedUser(); + return callback.onSuccess('SUCCESS'); + } + ); + return undefined; + } + + /** + * This is used for the user to signOut of the application and clear the cached tokens. + * @returns {void} + */ + signOut() { + this.signInUserSession = null; + this.clearCachedUser(); + } + + /** + * This is used by a user trying to select a given MFA + * @param {string} answerChallenge the mfa the user wants + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + sendMFASelectionAnswer(answerChallenge, callback) { + const challengeResponses = {}; + challengeResponses.USERNAME = this.username; + challengeResponses.ANSWER = answerChallenge; + + const jsonReq = { + ChallengeName: 'SELECT_MFA_TYPE', + ChallengeResponses: challengeResponses, + ClientId: this.pool.getClientId(), + Session: this.Session, + }; + if (this.getUserContextData()) { + jsonReq.UserContextData = this.getUserContextData(); + } + this.client.request('RespondToAuthChallenge', jsonReq, (err, data) => { + if (err) { + return callback.onFailure(err); + } + this.Session = data.Session; + if (answerChallenge === 'SMS_MFA') { + return callback.mfaRequired( + data.challengeName, + data.challengeParameters + ); + } + if (answerChallenge === 'SOFTWARE_TOKEN_MFA') { + return callback.totpRequired( + data.challengeName, + data.challengeParameters + ); + } + return undefined; + }); + } + + /** + * This returns the user context data for advanced security feature. + * @returns {void} + */ + getUserContextData() { + const pool = this.pool; + return pool.getUserContextData(this.username); + } + + /** + * This is used by an authenticated or a user trying to authenticate to associate a TOTP MFA + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + associateSoftwareToken(callback) { + if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { + this.client.request( + 'AssociateSoftwareToken', + { + Session: this.Session, + }, + (err, data) => { + if (err) { + return callback.onFailure(err); + } + this.Session = data.Session; + return callback.associateSecretCode(data.SecretCode); + } + ); + } else { + this.client.request( + 'AssociateSoftwareToken', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + }, + (err, data) => { + if (err) { + return callback.onFailure(err); + } + return callback.associateSecretCode(data.SecretCode); + } + ); + } + } + + /** + * This is used by an authenticated or a user trying to authenticate to verify a TOTP MFA + * @param {string} totpCode The MFA code entered by the user. + * @param {string} friendlyDeviceName The device name we are assigning to the device. + * @param {nodeCallback} callback Called on success or error. + * @returns {void} + */ + verifySoftwareToken(totpCode, friendlyDeviceName, callback) { + if (!(this.signInUserSession != null && this.signInUserSession.isValid())) { + this.client.request( + 'VerifySoftwareToken', + { + Session: this.Session, + UserCode: totpCode, + FriendlyDeviceName: friendlyDeviceName, + }, + (err, data) => { + if (err) { + return callback.onFailure(err); + } + this.Session = data.Session; + const challengeResponses = {}; + challengeResponses.USERNAME = this.username; + const jsonReq = { + ChallengeName: 'MFA_SETUP', + ClientId: this.pool.getClientId(), + ChallengeResponses: challengeResponses, + Session: this.Session, + }; + if (this.getUserContextData()) { + jsonReq.UserContextData = this.getUserContextData(); + } + this.client.request( + 'RespondToAuthChallenge', + jsonReq, + (errRespond, dataRespond) => { + if (errRespond) { + return callback.onFailure(errRespond); + } + this.signInUserSession = this.getCognitoUserSession( + dataRespond.AuthenticationResult + ); + this.cacheTokens(); + return callback.onSuccess(this.signInUserSession); + } + ); + return undefined; + } + ); + } else { + this.client.request( + 'VerifySoftwareToken', + { + AccessToken: this.signInUserSession.getAccessToken().getJwtToken(), + UserCode: totpCode, + FriendlyDeviceName: friendlyDeviceName, + }, + (err, data) => { + if (err) { + return callback.onFailure(err); + } + return callback.onSuccess(data); + } + ); + } + } } diff --git a/packages/amazon-cognito-identity-js/src/CognitoUserAttribute.js b/packages/amazon-cognito-identity-js/src/CognitoUserAttribute.js index 9d2959e92cd..da163cf87fe 100644 --- a/packages/amazon-cognito-identity-js/src/CognitoUserAttribute.js +++ b/packages/amazon-cognito-identity-js/src/CognitoUserAttribute.js @@ -17,64 +17,64 @@ /** @class */ export default class CognitoUserAttribute { - /** - * Constructs a new CognitoUserAttribute object - * @param {string=} Name The record's name - * @param {string=} Value The record's value - */ - constructor({ Name, Value } = {}) { - this.Name = Name || ''; - this.Value = Value || ''; - } + /** + * Constructs a new CognitoUserAttribute object + * @param {string=} Name The record's name + * @param {string=} Value The record's value + */ + constructor({ Name, Value } = {}) { + this.Name = Name || ''; + this.Value = Value || ''; + } - /** - * @returns {string} the record's value. - */ - getValue() { - return this.Value; - } + /** + * @returns {string} the record's value. + */ + getValue() { + return this.Value; + } - /** - * Sets the record's value. - * @param {string} value The new value. - * @returns {CognitoUserAttribute} The record for method chaining. - */ - setValue(value) { - this.Value = value; - return this; - } + /** + * Sets the record's value. + * @param {string} value The new value. + * @returns {CognitoUserAttribute} The record for method chaining. + */ + setValue(value) { + this.Value = value; + return this; + } - /** - * @returns {string} the record's name. - */ - getName() { - return this.Name; - } + /** + * @returns {string} the record's name. + */ + getName() { + return this.Name; + } - /** - * Sets the record's name - * @param {string} name The new name. - * @returns {CognitoUserAttribute} The record for method chaining. - */ - setName(name) { - this.Name = name; - return this; - } + /** + * Sets the record's name + * @param {string} name The new name. + * @returns {CognitoUserAttribute} The record for method chaining. + */ + setName(name) { + this.Name = name; + return this; + } - /** - * @returns {string} a string representation of the record. - */ - toString() { - return JSON.stringify(this); - } + /** + * @returns {string} a string representation of the record. + */ + toString() { + return JSON.stringify(this); + } - /** - * @returns {object} a flat object representing the record. - */ - toJSON() { - return { - Name: this.Name, - Value: this.Value, - }; - } + /** + * @returns {object} a flat object representing the record. + */ + toJSON() { + return { + Name: this.Name, + Value: this.Value, + }; + } } diff --git a/packages/amazon-cognito-identity-js/src/CognitoUserPool.js b/packages/amazon-cognito-identity-js/src/CognitoUserPool.js index 3b6a69d2615..2903c9b611f 100644 --- a/packages/amazon-cognito-identity-js/src/CognitoUserPool.js +++ b/packages/amazon-cognito-identity-js/src/CognitoUserPool.js @@ -21,151 +21,159 @@ import StorageHelper from './StorageHelper'; /** @class */ export default class CognitoUserPool { - /** - * Constructs a new CognitoUserPool object - * @param {object} data Creation options. - * @param {string} data.UserPoolId Cognito user pool id. - * @param {string} data.ClientId User pool application client id. - * @param {object} data.Storage Optional storage object. - * @param {boolean} data.AdvancedSecurityDataCollectionFlag Optional: - * boolean flag indicating if the data collection is enabled - * to support cognito advanced security features. By default, this - * flag is set to true. - */ - constructor(data) { - const { UserPoolId, ClientId, endpoint, AdvancedSecurityDataCollectionFlag } = data || {}; - if (!UserPoolId || !ClientId) { - throw new Error('Both UserPoolId and ClientId are required.'); - } - if (!/^[\w-]+_.+$/.test(UserPoolId)) { - throw new Error('Invalid UserPoolId format.'); - } - const region = UserPoolId.split('_')[0]; - - this.userPoolId = UserPoolId; - this.clientId = ClientId; - - this.client = new Client(region, endpoint); - - /** - * By default, AdvancedSecurityDataCollectionFlag is set to true, - * if no input value is provided. - */ - this.advancedSecurityDataCollectionFlag = AdvancedSecurityDataCollectionFlag !== false; - - this.storage = data.Storage || new StorageHelper().getStorage(); - } - - /** - * @returns {string} the user pool id - */ - getUserPoolId() { - return this.userPoolId; - } - - /** - * @returns {string} the client id - */ - getClientId() { - return this.clientId; - } - - /** - * @typedef {object} SignUpResult - * @property {CognitoUser} user New user. - * @property {bool} userConfirmed If the user is already confirmed. - */ - /** - * method for signing up a user - * @param {string} username User's username. - * @param {string} password Plain-text initial password entered by user. - * @param {(AttributeArg[])=} userAttributes New user attributes. - * @param {(AttributeArg[])=} validationData Application metadata. - * @param {nodeCallback} callback Called on error or with the new user. - * @returns {void} - */ - signUp(username, password, userAttributes, validationData, callback) { - const jsonReq = { - ClientId: this.clientId, - Username: username, - Password: password, - UserAttributes: userAttributes, - ValidationData: validationData, - }; - if (this.getUserContextData(username)) { - jsonReq.UserContextData = this.getUserContextData(username); - } - this.client.request('SignUp', jsonReq, (err, data) => { - if (err) { - return callback(err, null); - } - - const cognitoUser = { - Username: username, - Pool: this, - Storage: this.storage, - }; - - const returnData = { - user: new CognitoUser(cognitoUser), - userConfirmed: data.UserConfirmed, - userSub: data.UserSub, - codeDeliveryDetails: data.CodeDeliveryDetails, - }; - - return callback(null, returnData); - }); - } - - - /** - * method for getting the current user of the application from the local storage - * - * @returns {CognitoUser} the user retrieved from storage - */ - getCurrentUser() { - const lastUserKey = `CognitoIdentityServiceProvider.${this.clientId}.LastAuthUser`; - - const lastAuthUser = this.storage.getItem(lastUserKey); - if (lastAuthUser) { - const cognitoUser = { - Username: lastAuthUser, - Pool: this, - Storage: this.storage, - }; - - return new CognitoUser(cognitoUser); - } - - return null; - } - - /** - * This method returns the encoded data string used for cognito advanced security feature. - * This would be generated only when developer has included the JS used for collecting the - * data on their client. Please refer to documentation to know more about using AdvancedSecurity - * features - * @param {string} username the username for the context data - * @returns {string} the user context data - **/ - getUserContextData(username) { - if (typeof AmazonCognitoAdvancedSecurityData === 'undefined') { - return undefined; - } - /* eslint-disable */ - const amazonCognitoAdvancedSecurityDataConst = AmazonCognitoAdvancedSecurityData; - /* eslint-enable */ - - if (this.advancedSecurityDataCollectionFlag) { - const advancedSecurityData = amazonCognitoAdvancedSecurityDataConst.getData(username, - this.userPoolId, this.clientId); - if (advancedSecurityData) { - const userContextData = { - EncodedData: advancedSecurityData, - }; - return userContextData; - } - } - return {}; - } + /** + * Constructs a new CognitoUserPool object + * @param {object} data Creation options. + * @param {string} data.UserPoolId Cognito user pool id. + * @param {string} data.ClientId User pool application client id. + * @param {object} data.Storage Optional storage object. + * @param {boolean} data.AdvancedSecurityDataCollectionFlag Optional: + * boolean flag indicating if the data collection is enabled + * to support cognito advanced security features. By default, this + * flag is set to true. + */ + constructor(data) { + const { + UserPoolId, + ClientId, + endpoint, + AdvancedSecurityDataCollectionFlag, + } = data || {}; + if (!UserPoolId || !ClientId) { + throw new Error('Both UserPoolId and ClientId are required.'); + } + if (!/^[\w-]+_.+$/.test(UserPoolId)) { + throw new Error('Invalid UserPoolId format.'); + } + const region = UserPoolId.split('_')[0]; + + this.userPoolId = UserPoolId; + this.clientId = ClientId; + + this.client = new Client(region, endpoint); + + /** + * By default, AdvancedSecurityDataCollectionFlag is set to true, + * if no input value is provided. + */ + this.advancedSecurityDataCollectionFlag = + AdvancedSecurityDataCollectionFlag !== false; + + this.storage = data.Storage || new StorageHelper().getStorage(); + } + + /** + * @returns {string} the user pool id + */ + getUserPoolId() { + return this.userPoolId; + } + + /** + * @returns {string} the client id + */ + getClientId() { + return this.clientId; + } + + /** + * @typedef {object} SignUpResult + * @property {CognitoUser} user New user. + * @property {bool} userConfirmed If the user is already confirmed. + */ + /** + * method for signing up a user + * @param {string} username User's username. + * @param {string} password Plain-text initial password entered by user. + * @param {(AttributeArg[])=} userAttributes New user attributes. + * @param {(AttributeArg[])=} validationData Application metadata. + * @param {nodeCallback} callback Called on error or with the new user. + * @returns {void} + */ + signUp(username, password, userAttributes, validationData, callback) { + const jsonReq = { + ClientId: this.clientId, + Username: username, + Password: password, + UserAttributes: userAttributes, + ValidationData: validationData, + }; + if (this.getUserContextData(username)) { + jsonReq.UserContextData = this.getUserContextData(username); + } + this.client.request('SignUp', jsonReq, (err, data) => { + if (err) { + return callback(err, null); + } + + const cognitoUser = { + Username: username, + Pool: this, + Storage: this.storage, + }; + + const returnData = { + user: new CognitoUser(cognitoUser), + userConfirmed: data.UserConfirmed, + userSub: data.UserSub, + codeDeliveryDetails: data.CodeDeliveryDetails, + }; + + return callback(null, returnData); + }); + } + + /** + * method for getting the current user of the application from the local storage + * + * @returns {CognitoUser} the user retrieved from storage + */ + getCurrentUser() { + const lastUserKey = `CognitoIdentityServiceProvider.${this.clientId}.LastAuthUser`; + + const lastAuthUser = this.storage.getItem(lastUserKey); + if (lastAuthUser) { + const cognitoUser = { + Username: lastAuthUser, + Pool: this, + Storage: this.storage, + }; + + return new CognitoUser(cognitoUser); + } + + return null; + } + + /** + * This method returns the encoded data string used for cognito advanced security feature. + * This would be generated only when developer has included the JS used for collecting the + * data on their client. Please refer to documentation to know more about using AdvancedSecurity + * features + * @param {string} username the username for the context data + * @returns {string} the user context data + **/ + getUserContextData(username) { + if (typeof AmazonCognitoAdvancedSecurityData === 'undefined') { + return undefined; + } + /* eslint-disable */ + const amazonCognitoAdvancedSecurityDataConst = AmazonCognitoAdvancedSecurityData; + /* eslint-enable */ + + if (this.advancedSecurityDataCollectionFlag) { + const advancedSecurityData = amazonCognitoAdvancedSecurityDataConst.getData( + username, + this.userPoolId, + this.clientId + ); + if (advancedSecurityData) { + const userContextData = { + EncodedData: advancedSecurityData, + }; + return userContextData; + } + } + return {}; + } } diff --git a/packages/amazon-cognito-identity-js/src/CognitoUserSession.js b/packages/amazon-cognito-identity-js/src/CognitoUserSession.js index 5fa3f8e469e..9244deb89f4 100644 --- a/packages/amazon-cognito-identity-js/src/CognitoUserSession.js +++ b/packages/amazon-cognito-identity-js/src/CognitoUserSession.js @@ -17,71 +17,78 @@ /** @class */ export default class CognitoUserSession { - /** - * Constructs a new CognitoUserSession object - * @param {CognitoIdToken} IdToken The session's Id token. - * @param {CognitoRefreshToken=} RefreshToken The session's refresh token. - * @param {CognitoAccessToken} AccessToken The session's access token. - * @param {int} ClockDrift The saved computer's clock drift or undefined to force calculation. - */ - constructor({ IdToken, RefreshToken, AccessToken, ClockDrift } = {}) { - if (AccessToken == null || IdToken == null) { - throw new Error('Id token and Access Token must be present.'); - } + /** + * Constructs a new CognitoUserSession object + * @param {CognitoIdToken} IdToken The session's Id token. + * @param {CognitoRefreshToken=} RefreshToken The session's refresh token. + * @param {CognitoAccessToken} AccessToken The session's access token. + * @param {int} ClockDrift The saved computer's clock drift or undefined to force calculation. + */ + constructor({ IdToken, RefreshToken, AccessToken, ClockDrift } = {}) { + if (AccessToken == null || IdToken == null) { + throw new Error('Id token and Access Token must be present.'); + } - this.idToken = IdToken; - this.refreshToken = RefreshToken; - this.accessToken = AccessToken; - this.clockDrift = ClockDrift === undefined ? this.calculateClockDrift() : ClockDrift; - } + this.idToken = IdToken; + this.refreshToken = RefreshToken; + this.accessToken = AccessToken; + this.clockDrift = + ClockDrift === undefined ? this.calculateClockDrift() : ClockDrift; + } - /** - * @returns {CognitoIdToken} the session's Id token - */ - getIdToken() { - return this.idToken; - } + /** + * @returns {CognitoIdToken} the session's Id token + */ + getIdToken() { + return this.idToken; + } - /** - * @returns {CognitoRefreshToken} the session's refresh token - */ - getRefreshToken() { - return this.refreshToken; - } + /** + * @returns {CognitoRefreshToken} the session's refresh token + */ + getRefreshToken() { + return this.refreshToken; + } - /** - * @returns {CognitoAccessToken} the session's access token - */ - getAccessToken() { - return this.accessToken; - } + /** + * @returns {CognitoAccessToken} the session's access token + */ + getAccessToken() { + return this.accessToken; + } - /** - * @returns {int} the session's clock drift - */ - getClockDrift() { - return this.clockDrift; - } + /** + * @returns {int} the session's clock drift + */ + getClockDrift() { + return this.clockDrift; + } - /** - * @returns {int} the computer's clock drift - */ - calculateClockDrift() { - const now = Math.floor(new Date() / 1000); - const iat = Math.min(this.accessToken.getIssuedAt(), this.idToken.getIssuedAt()); + /** + * @returns {int} the computer's clock drift + */ + calculateClockDrift() { + const now = Math.floor(new Date() / 1000); + const iat = Math.min( + this.accessToken.getIssuedAt(), + this.idToken.getIssuedAt() + ); - return now - iat; - } + return now - iat; + } - /** - * Checks to see if the session is still valid based on session expiry information found - * in tokens and the current time (adjusted with clock drift) - * @returns {boolean} if the session is still valid - */ - isValid() { - const now = Math.floor(new Date() / 1000); - const adjusted = now - this.clockDrift; + /** + * Checks to see if the session is still valid based on session expiry information found + * in tokens and the current time (adjusted with clock drift) + * @returns {boolean} if the session is still valid + */ + isValid() { + const now = Math.floor(new Date() / 1000); + const adjusted = now - this.clockDrift; - return adjusted < this.accessToken.getExpiration() && adjusted < this.idToken.getExpiration(); - } + return ( + adjusted < this.accessToken.getExpiration() && + adjusted < this.idToken.getExpiration() + ); + } } diff --git a/packages/amazon-cognito-identity-js/src/CookieStorage.js b/packages/amazon-cognito-identity-js/src/CookieStorage.js index b3076f8d05f..2116e35da35 100644 --- a/packages/amazon-cognito-identity-js/src/CookieStorage.js +++ b/packages/amazon-cognito-identity-js/src/CookieStorage.js @@ -1,91 +1,87 @@ - import * as Cookies from 'js-cookie'; /** @class */ export default class CookieStorage { + /** + * Constructs a new CookieStorage object + * @param {object} data Creation options. + * @param {string} data.domain Cookies domain (mandatory). + * @param {string} data.path Cookies path (default: '/') + * @param {integer} data.expires Cookie expiration (in days, default: 365) + * @param {boolean} data.secure Cookie secure flag (default: true) + */ + constructor(data) { + if (data.domain) { + this.domain = data.domain; + } else { + throw new Error('The domain of cookieStorage can not be undefined.'); + } + if (data.path) { + this.path = data.path; + } else { + this.path = '/'; + } + if (Object.prototype.hasOwnProperty.call(data, 'expires')) { + this.expires = data.expires; + } else { + this.expires = 365; + } + if (Object.prototype.hasOwnProperty.call(data, 'secure')) { + this.secure = data.secure; + } else { + this.secure = true; + } + } - /** - * Constructs a new CookieStorage object - * @param {object} data Creation options. - * @param {string} data.domain Cookies domain (mandatory). - * @param {string} data.path Cookies path (default: '/') - * @param {integer} data.expires Cookie expiration (in days, default: 365) - * @param {boolean} data.secure Cookie secure flag (default: true) - */ - constructor(data) { - if (data.domain) { - this.domain = data.domain; - } else { - throw new Error('The domain of cookieStorage can not be undefined.'); - } - if (data.path) { - this.path = data.path; - } else { - this.path = '/'; - } - if (Object.prototype.hasOwnProperty.call(data, 'expires')) { - this.expires = data.expires; - } else { - this.expires = 365; - } - if (Object.prototype.hasOwnProperty.call(data, 'secure')) { - this.secure = data.secure; - } else { - this.secure = true; - } - } - - /** - * This is used to set a specific item in storage - * @param {string} key - the key for the item - * @param {object} value - the value - * @returns {string} value that was set - */ - setItem(key, value) { - Cookies.set(key, value, { - path: this.path, - expires: this.expires, - domain: this.domain, - secure: this.secure, - } - ); - return Cookies.get(key); - } + /** + * This is used to set a specific item in storage + * @param {string} key - the key for the item + * @param {object} value - the value + * @returns {string} value that was set + */ + setItem(key, value) { + Cookies.set(key, value, { + path: this.path, + expires: this.expires, + domain: this.domain, + secure: this.secure, + }); + return Cookies.get(key); + } - /** - * This is used to get a specific key from storage - * @param {string} key - the key for the item - * This is used to clear the storage - * @returns {string} the data item - */ - getItem(key) { - return Cookies.get(key); - } + /** + * This is used to get a specific key from storage + * @param {string} key - the key for the item + * This is used to clear the storage + * @returns {string} the data item + */ + getItem(key) { + return Cookies.get(key); + } - /** - * This is used to remove an item from storage - * @param {string} key - the key being set - * @returns {string} value - value that was deleted - */ - removeItem(key) { - return Cookies.remove(key, { - path: this.path, - domain: this.domain, - secure: this.secure, - } - ); - } + /** + * This is used to remove an item from storage + * @param {string} key - the key being set + * @returns {string} value - value that was deleted + */ + removeItem(key) { + return Cookies.remove(key, { + path: this.path, + domain: this.domain, + secure: this.secure, + }); + } - /** - * This is used to clear the storage - * @returns {string} nothing - */ - clear() { - const cookies = Cookies.get(); - let index; - for (index = 0; index < cookies.length; ++index) { - Cookies.remove(cookies[index]); - } - return {}; - } + /** + * This is used to clear the storage + * @returns {string} nothing + */ + clear() { + const cookies = Cookies.get(); + let index; + for (index = 0; index < cookies.length; ++index) { + Cookies.remove(cookies[index]); + } + return {}; + } } diff --git a/packages/amazon-cognito-identity-js/src/DateHelper.js b/packages/amazon-cognito-identity-js/src/DateHelper.js index 2fa677c84a3..de35bda1375 100644 --- a/packages/amazon-cognito-identity-js/src/DateHelper.js +++ b/packages/amazon-cognito-identity-js/src/DateHelper.js @@ -15,42 +15,54 @@ * limitations under the License. */ -const monthNames = - ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; +const monthNames = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', +]; const weekNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; /** @class */ export default class DateHelper { - /** - * @returns {string} The current time in "ddd MMM D HH:mm:ss UTC YYYY" format. - */ - getNowString() { - const now = new Date(); - - const weekDay = weekNames[now.getUTCDay()]; - const month = monthNames[now.getUTCMonth()]; - const day = now.getUTCDate(); - - let hours = now.getUTCHours(); - if (hours < 10) { - hours = `0${hours}`; - } - - let minutes = now.getUTCMinutes(); - if (minutes < 10) { - minutes = `0${minutes}`; - } - - let seconds = now.getUTCSeconds(); - if (seconds < 10) { - seconds = `0${seconds}`; - } - - const year = now.getUTCFullYear(); - - // ddd MMM D HH:mm:ss UTC YYYY - const dateNow = `${weekDay} ${month} ${day} ${hours}:${minutes}:${seconds} UTC ${year}`; - - return dateNow; - } + /** + * @returns {string} The current time in "ddd MMM D HH:mm:ss UTC YYYY" format. + */ + getNowString() { + const now = new Date(); + + const weekDay = weekNames[now.getUTCDay()]; + const month = monthNames[now.getUTCMonth()]; + const day = now.getUTCDate(); + + let hours = now.getUTCHours(); + if (hours < 10) { + hours = `0${hours}`; + } + + let minutes = now.getUTCMinutes(); + if (minutes < 10) { + minutes = `0${minutes}`; + } + + let seconds = now.getUTCSeconds(); + if (seconds < 10) { + seconds = `0${seconds}`; + } + + const year = now.getUTCFullYear(); + + // ddd MMM D HH:mm:ss UTC YYYY + const dateNow = `${weekDay} ${month} ${day} ${hours}:${minutes}:${seconds} UTC ${year}`; + + return dateNow; + } } diff --git a/packages/amazon-cognito-identity-js/src/StorageHelper-rn.js b/packages/amazon-cognito-identity-js/src/StorageHelper-rn.js index 92912109c62..221b92a1f4c 100644 --- a/packages/amazon-cognito-identity-js/src/StorageHelper-rn.js +++ b/packages/amazon-cognito-identity-js/src/StorageHelper-rn.js @@ -22,90 +22,90 @@ let dataMemory = {}; /** @class */ class MemoryStorage { + /** + * This is used to set a specific item in storage + * @param {string} key - the key for the item + * @param {object} value - the value + * @returns {string} value that was set + */ + static setItem(key, value) { + AsyncStorage.setItem(MEMORY_KEY_PREFIX + key, value); + dataMemory[key] = value; + return dataMemory[key]; + } - /** - * This is used to set a specific item in storage - * @param {string} key - the key for the item - * @param {object} value - the value - * @returns {string} value that was set - */ - static setItem(key, value) { - AsyncStorage.setItem(MEMORY_KEY_PREFIX + key, value); - dataMemory[key] = value; - return dataMemory[key]; - } + /** + * This is used to get a specific key from storage + * @param {string} key - the key for the item + * This is used to clear the storage + * @returns {string} the data item + */ + static getItem(key) { + return Object.prototype.hasOwnProperty.call(dataMemory, key) + ? dataMemory[key] + : undefined; + } - /** - * This is used to get a specific key from storage - * @param {string} key - the key for the item - * This is used to clear the storage - * @returns {string} the data item - */ - static getItem(key) { - return Object.prototype.hasOwnProperty.call(dataMemory, key) ? dataMemory[key] : undefined; - } + /** + * This is used to remove an item from storage + * @param {string} key - the key being set + * @returns {string} value - value that was deleted + */ + static removeItem(key) { + AsyncStorage.removeItem(MEMORY_KEY_PREFIX + key); + return delete dataMemory[key]; + } - /** - * This is used to remove an item from storage - * @param {string} key - the key being set - * @returns {string} value - value that was deleted - */ - static removeItem(key) { - AsyncStorage.removeItem(MEMORY_KEY_PREFIX + key); - return delete dataMemory[key]; - } + /** + * This is used to clear the storage + * @returns {string} nothing + */ + static clear() { + dataMemory = {}; + return dataMemory; + } - /** - * This is used to clear the storage - * @returns {string} nothing - */ - static clear() { - dataMemory = {}; - return dataMemory; - } - - /** - * Will sync the MemoryStorage data from AsyncStorage to storageWindow MemoryStorage - * @param {nodeCallback} callback callback with (err, 'SUCCESS') - * @returns {void} - */ - static sync(callback) { - AsyncStorage.getAllKeys((errKeys, keys) => { - if (errKeys) return callback(errKeys, null); - const memoryKeys = keys.filter((key) => key.startsWith(MEMORY_KEY_PREFIX)); - AsyncStorage.multiGet(memoryKeys, (err, stores) => { - if (err) return callback(err, null); - stores.map((result, index, store) => { - const key = store[index][0]; - const value = store[index][1]; - const memoryKey = key.replace(MEMORY_KEY_PREFIX, ''); - dataMemory[memoryKey] = value; - return undefined; - }); - callback(null, 'SUCCESS'); - return undefined; - }); - return undefined; - }); - } + /** + * Will sync the MemoryStorage data from AsyncStorage to storageWindow MemoryStorage + * @param {nodeCallback} callback callback with (err, 'SUCCESS') + * @returns {void} + */ + static sync(callback) { + AsyncStorage.getAllKeys((errKeys, keys) => { + if (errKeys) return callback(errKeys, null); + const memoryKeys = keys.filter(key => key.startsWith(MEMORY_KEY_PREFIX)); + AsyncStorage.multiGet(memoryKeys, (err, stores) => { + if (err) return callback(err, null); + stores.map((result, index, store) => { + const key = store[index][0]; + const value = store[index][1]; + const memoryKey = key.replace(MEMORY_KEY_PREFIX, ''); + dataMemory[memoryKey] = value; + return undefined; + }); + callback(null, 'SUCCESS'); + return undefined; + }); + return undefined; + }); + } } /** @class */ export default class StorageHelper { + /** + * This is used to get a storage object + * @returns {object} the storage + */ + constructor() { + this.storageWindow = MemoryStorage; + } - /** - * This is used to get a storage object - * @returns {object} the storage - */ - constructor() { - this.storageWindow = MemoryStorage; - } - - /** - * This is used to return the storage - * @returns {object} the storage - */ - getStorage() { - return this.storageWindow; - } + /** + * This is used to return the storage + * @returns {object} the storage + */ + getStorage() { + return this.storageWindow; + } } diff --git a/packages/amazon-cognito-identity-js/src/StorageHelper.js b/packages/amazon-cognito-identity-js/src/StorageHelper.js index 4ac19fc5ae7..71bb27f7f93 100644 --- a/packages/amazon-cognito-identity-js/src/StorageHelper.js +++ b/packages/amazon-cognito-identity-js/src/StorageHelper.js @@ -19,69 +19,69 @@ let dataMemory = {}; /** @class */ class MemoryStorage { + /** + * This is used to set a specific item in storage + * @param {string} key - the key for the item + * @param {object} value - the value + * @returns {string} value that was set + */ + static setItem(key, value) { + dataMemory[key] = value; + return dataMemory[key]; + } - /** - * This is used to set a specific item in storage - * @param {string} key - the key for the item - * @param {object} value - the value - * @returns {string} value that was set - */ - static setItem(key, value) { - dataMemory[key] = value; - return dataMemory[key]; - } + /** + * This is used to get a specific key from storage + * @param {string} key - the key for the item + * This is used to clear the storage + * @returns {string} the data item + */ + static getItem(key) { + return Object.prototype.hasOwnProperty.call(dataMemory, key) + ? dataMemory[key] + : undefined; + } - /** - * This is used to get a specific key from storage - * @param {string} key - the key for the item - * This is used to clear the storage - * @returns {string} the data item - */ - static getItem(key) { - return Object.prototype.hasOwnProperty.call(dataMemory, key) ? dataMemory[key] : undefined; - } + /** + * This is used to remove an item from storage + * @param {string} key - the key being set + * @returns {string} value - value that was deleted + */ + static removeItem(key) { + return delete dataMemory[key]; + } - /** - * This is used to remove an item from storage - * @param {string} key - the key being set - * @returns {string} value - value that was deleted - */ - static removeItem(key) { - return delete dataMemory[key]; - } - - /** - * This is used to clear the storage - * @returns {string} nothing - */ - static clear() { - dataMemory = {}; - return dataMemory; - } + /** + * This is used to clear the storage + * @returns {string} nothing + */ + static clear() { + dataMemory = {}; + return dataMemory; + } } /** @class */ export default class StorageHelper { + /** + * This is used to get a storage object + * @returns {object} the storage + */ + constructor() { + try { + this.storageWindow = window.localStorage; + this.storageWindow.setItem('aws.cognito.test-ls', 1); + this.storageWindow.removeItem('aws.cognito.test-ls'); + } catch (exception) { + this.storageWindow = MemoryStorage; + } + } - /** - * This is used to get a storage object - * @returns {object} the storage - */ - constructor() { - try { - this.storageWindow = window.localStorage; - this.storageWindow.setItem('aws.cognito.test-ls', 1); - this.storageWindow.removeItem('aws.cognito.test-ls'); - } catch (exception) { - this.storageWindow = MemoryStorage; - } - } - - /** - * This is used to return the storage - * @returns {object} the storage - */ - getStorage() { - return this.storageWindow; - } + /** + * This is used to return the storage + * @returns {object} the storage + */ + getStorage() { + return this.storageWindow; + } } diff --git a/packages/amazon-cognito-identity-js/src/UserAgent.js b/packages/amazon-cognito-identity-js/src/UserAgent.js index 7ead870390b..6f57f470555 100644 --- a/packages/amazon-cognito-identity-js/src/UserAgent.js +++ b/packages/amazon-cognito-identity-js/src/UserAgent.js @@ -3,4 +3,4 @@ export default UserAgent; // constructor function UserAgent() {} // public -UserAgent.prototype.userAgent = 'aws-amplify/0.1.x js'; \ No newline at end of file +UserAgent.prototype.userAgent = 'aws-amplify/0.1.x js'; diff --git a/packages/amazon-cognito-identity-js/webpack.config.js b/packages/amazon-cognito-identity-js/webpack.config.js index f20133e2115..7f336961f80 100644 --- a/packages/amazon-cognito-identity-js/webpack.config.js +++ b/packages/amazon-cognito-identity-js/webpack.config.js @@ -1,65 +1,67 @@ // version 3.11.0 const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); -const CompressionPlugin = require("compression-webpack-plugin") +const CompressionPlugin = require('compression-webpack-plugin'); /* eslint-disable */ var webpack = require('webpack'); -var banner = '/*!\n' + -' * Copyright 2016 Amazon.com,\n' + -' * Inc. or its affiliates. All Rights Reserved.\n' + -' * \n' + -' * Licensed under the Amazon Software License (the "License").\n' + -' * You may not use this file except in compliance with the\n' + -' * License. A copy of the License is located at\n' + -' * \n' + -' * http://aws.amazon.com/asl/\n' + -' * \n' + -' * or in the "license" file accompanying this file. This file is\n' + -' * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n' + -' * CONDITIONS OF ANY KIND, express or implied. See the License\n' + -' * for the specific language governing permissions and\n' + -' * limitations under the License. \n' + -' */\n\n'; +var banner = + '/*!\n' + + ' * Copyright 2016 Amazon.com,\n' + + ' * Inc. or its affiliates. All Rights Reserved.\n' + + ' * \n' + + ' * Licensed under the Amazon Software License (the "License").\n' + + ' * You may not use this file except in compliance with the\n' + + ' * License. A copy of the License is located at\n' + + ' * \n' + + ' * http://aws.amazon.com/asl/\n' + + ' * \n' + + ' * or in the "license" file accompanying this file. This file is\n' + + ' * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n' + + ' * CONDITIONS OF ANY KIND, express or implied. See the License\n' + + ' * for the specific language governing permissions and\n' + + ' * limitations under the License. \n' + + ' */\n\n'; var config = { - entry: { - 'amazon-cognito-identity': './src/index.js', - 'amazon-cognito-identity.min': './src/index.js' - }, - output: { - filename: '[name].js', - path: __dirname + '/dist', - libraryTarget: 'umd', - library: 'AmazonCognitoIdentity', - devtoolModuleFilenameTemplate: require('../aws-amplify/webpack-utils').devtoolModuleFilenameTemplate - }, - plugins: [ - new webpack.optimize.OccurrenceOrderPlugin(), - new webpack.BannerPlugin({ banner, raw: true }), - new UglifyJsPlugin({ - minimize: true, - sourceMap: true, - include: /\.min\.js$/, - }), - new CompressionPlugin({ - include: /\.min\.js$/, - }) - ], - module: { - rules: [ - // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. - //{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' }, - { - test: /\.js$/, - exclude: /node_modules/, - loader: 'babel-loader', - query: { - cacheDirectory: './node_modules/.cache/babel' - } - } - ] - } + entry: { + 'amazon-cognito-identity': './src/index.js', + 'amazon-cognito-identity.min': './src/index.js', + }, + output: { + filename: '[name].js', + path: __dirname + '/dist', + libraryTarget: 'umd', + library: 'AmazonCognitoIdentity', + devtoolModuleFilenameTemplate: require('../aws-amplify/webpack-utils') + .devtoolModuleFilenameTemplate, + }, + plugins: [ + new webpack.optimize.OccurrenceOrderPlugin(), + new webpack.BannerPlugin({ banner, raw: true }), + new UglifyJsPlugin({ + minimize: true, + sourceMap: true, + include: /\.min\.js$/, + }), + new CompressionPlugin({ + include: /\.min\.js$/, + }), + ], + module: { + rules: [ + // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. + //{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' }, + { + test: /\.js$/, + exclude: /node_modules/, + loader: 'babel-loader', + query: { + cacheDirectory: './node_modules/.cache/babel', + }, + }, + ], + }, }; module.exports = config; diff --git a/packages/amplify-ui/CHANGELOG.md b/packages/amplify-ui/CHANGELOG.md index 83a9737f07d..7d539c21c76 100644 --- a/packages/amplify-ui/CHANGELOG.md +++ b/packages/amplify-ui/CHANGELOG.md @@ -7,368 +7,279 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package @aws-amplify/ui - - - - ## [1.0.23](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.22...@aws-amplify/ui@1.0.23) (2019-07-30) **Note:** Version bump only for package @aws-amplify/ui - - - - ## [1.0.22](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.20...@aws-amplify/ui@1.0.22) (2019-07-18) **Note:** Version bump only for package @aws-amplify/ui - - - - -## [1.0.21-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.20...@aws-amplify/ui@1.0.21-unstable.0) (2019-07-12) +## [1.0.21-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.20...@aws-amplify/ui@1.0.21-unstable.0) (2019-07-12) ### Bug Fixes -* **@aws-amplify/ui:** Fix the issue that window is not defined in [@aws-amplify](https://github.com/aws-amplify)/ui in NodeJS ([#3512](https://github.com/aws-amplify/amplify-js/issues/3512)) ([f290a00](https://github.com/aws-amplify/amplify-js/commit/f290a00)) - - - +- **@aws-amplify/ui:** Fix the issue that window is not defined in [@aws-amplify](https://github.com/aws-amplify)/ui in NodeJS ([#3512](https://github.com/aws-amplify/amplify-js/issues/3512)) ([f290a00](https://github.com/aws-amplify/amplify-js/commit/f290a00)) -## [1.0.20](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.20-unstable.1...@aws-amplify/ui@1.0.20) (2019-06-17) - - +## [1.0.20](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.20-unstable.1...@aws-amplify/ui@1.0.20) (2019-06-17) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.20-unstable.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.20-unstable.0...@aws-amplify/ui@1.0.20-unstable.1) (2019-06-03) - - +## [1.0.20-unstable.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.20-unstable.0...@aws-amplify/ui@1.0.20-unstable.1) (2019-06-03) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.20-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.19...@aws-amplify/ui@1.0.20-unstable.0) (2019-05-24) - - +## [1.0.20-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.19...@aws-amplify/ui@1.0.20-unstable.0) (2019-05-24) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.19](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.19-unstable.1...@aws-amplify/ui@1.0.19) (2019-05-06) - - +## [1.0.19](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.19-unstable.1...@aws-amplify/ui@1.0.19) (2019-05-06) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.19-unstable.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.19-unstable.0...@aws-amplify/ui@1.0.19-unstable.1) (2019-04-19) - - +## [1.0.19-unstable.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.19-unstable.0...@aws-amplify/ui@1.0.19-unstable.1) (2019-04-19) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.19-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.18...@aws-amplify/ui@1.0.19-unstable.0) (2019-04-12) - - +## [1.0.19-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.18...@aws-amplify/ui@1.0.19-unstable.0) (2019-04-12) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.18](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.18-unstable.0...@aws-amplify/ui@1.0.18) (2019-03-28) - - +## [1.0.18](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.18-unstable.0...@aws-amplify/ui@1.0.18) (2019-03-28) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.18-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.17...@aws-amplify/ui@1.0.18-unstable.0) (2019-03-07) - - +## [1.0.18-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.17...@aws-amplify/ui@1.0.18-unstable.0) (2019-03-07) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.17](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.17-unstable.0...@aws-amplify/ui@1.0.17) (2019-03-06) - - +## [1.0.17](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.17-unstable.0...@aws-amplify/ui@1.0.17) (2019-03-06) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.17-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.16...@aws-amplify/ui@1.0.17-unstable.0) (2019-03-04) - - +## [1.0.17-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.16...@aws-amplify/ui@1.0.17-unstable.0) (2019-03-04) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.16](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.16-unstable.0...@aws-amplify/ui@1.0.16) (2019-03-04) - - +## [1.0.16](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.16-unstable.0...@aws-amplify/ui@1.0.16) (2019-03-04) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.16-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.15...@aws-amplify/ui@1.0.16-unstable.0) (2019-01-21) - - +## [1.0.16-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.15...@aws-amplify/ui@1.0.16-unstable.0) (2019-01-21) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.14...@aws-amplify/ui@1.0.15) (2019-01-10) - - +## [1.0.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.14...@aws-amplify/ui@1.0.15) (2019-01-10) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.13-unstable.0...@aws-amplify/ui@1.0.14) (2018-12-15) - - +## [1.0.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.13-unstable.0...@aws-amplify/ui@1.0.14) (2018-12-15) **Note:** Version bump only for package @aws-amplify/ui + ## [1.0.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.12...@aws-amplify/ui@1.0.13) (2018-12-14) -## [1.0.13-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.12...@aws-amplify/ui@1.0.13-unstable.0) (2018-12-14) - - - +## [1.0.13-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.12...@aws-amplify/ui@1.0.13-unstable.0) (2018-12-14) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.12-unstable.0...@aws-amplify/ui@1.0.12) (2018-12-14) - - +## [1.0.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.12-unstable.0...@aws-amplify/ui@1.0.12) (2018-12-14) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.12-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.11...@aws-amplify/ui@1.0.12-unstable.0) (2018-12-13) +## [1.0.12-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.11...@aws-amplify/ui@1.0.12-unstable.0) (2018-12-13) ### Features -* **@aws-amplify/interactions @aws-amplify/react @aws-amplify/react-native @aws-amplify/angular @aws-amplify/vue:** Update interactions to include voice ([#2121](https://github.com/aws-amplify/amplify-js/issues/2121)) ([938d2a5](https://github.com/aws-amplify/amplify-js/commit/938d2a5)) - - - +- **@aws-amplify/interactions @aws-amplify/react @aws-amplify/react-native @aws-amplify/angular @aws-amplify/vue:** Update interactions to include voice ([#2121](https://github.com/aws-amplify/amplify-js/issues/2121)) ([938d2a5](https://github.com/aws-amplify/amplify-js/commit/938d2a5)) -## [1.0.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.11-unstable.0...@aws-amplify/ui@1.0.11) (2018-12-13) - - +## [1.0.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.11-unstable.0...@aws-amplify/ui@1.0.11) (2018-12-13) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.11-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.10...@aws-amplify/ui@1.0.11-unstable.0) (2018-12-10) - - +## [1.0.11-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.10...@aws-amplify/ui@1.0.11-unstable.0) (2018-12-10) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.10-unstable.1...@aws-amplify/ui@1.0.10) (2018-12-03) - - +## [1.0.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.10-unstable.1...@aws-amplify/ui@1.0.10) (2018-12-03) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.10-unstable.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.10-unstable.0...@aws-amplify/ui@1.0.10-unstable.1) (2018-11-30) +## [1.0.10-unstable.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.10-unstable.0...@aws-amplify/ui@1.0.10-unstable.1) (2018-11-30) ### Features -* **aws-amplify-react:** disable sign in button while loading ([#2216](https://github.com/aws-amplify/amplify-js/issues/2216)) ([b196b7f](https://github.com/aws-amplify/amplify-js/commit/b196b7f)) - +- **aws-amplify-react:** disable sign in button while loading ([#2216](https://github.com/aws-amplify/amplify-js/issues/2216)) ([b196b7f](https://github.com/aws-amplify/amplify-js/commit/b196b7f)) -## [1.0.10-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.9...@aws-amplify/ui@1.0.10-unstable.0) (2018-11-26) - +## [1.0.10-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.9...@aws-amplify/ui@1.0.10-unstable.0) (2018-11-26) -## [1.0.10-beta.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.10-beta.1...@aws-amplify/ui@1.0.10-beta.2) (2018-11-19) +## [1.0.10-beta.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.10-beta.1...@aws-amplify/ui@1.0.10-beta.2) (2018-11-19) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.10-beta.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.10-beta.0...@aws-amplify/ui@1.0.10-beta.1) (2018-11-14) - - +## [1.0.10-beta.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.10-beta.0...@aws-amplify/ui@1.0.10-beta.1) (2018-11-14) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.10-beta.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.9-unstable.0...@aws-amplify/ui@1.0.10-beta.0) (2018-11-02) +## [1.0.10-beta.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.9-unstable.0...@aws-amplify/ui@1.0.10-beta.0) (2018-11-02) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.9-unstable.0...@aws-amplify/ui@1.0.9) (2018-11-01) +## [1.0.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.9-unstable.0...@aws-amplify/ui@1.0.9) (2018-11-01) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.9-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.8...@aws-amplify/ui@1.0.9-unstable.0) (2018-10-30) +## [1.0.9-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.8...@aws-amplify/ui@1.0.9-unstable.0) (2018-10-30) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.8-unstable.0...@aws-amplify/ui@1.0.8) (2018-10-29) - - +## [1.0.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.8-unstable.0...@aws-amplify/ui@1.0.8) (2018-10-29) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.8-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.7...@aws-amplify/ui@1.0.8-unstable.0) (2018-10-29) +## [1.0.8-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.7...@aws-amplify/ui@1.0.8-unstable.0) (2018-10-29) ### Features -* **aws-amplify-react:** Add Auth0 button ([b16ded3](https://github.com/aws-amplify/amplify-js/commit/b16ded3)) - - - +- **aws-amplify-react:** Add Auth0 button ([b16ded3](https://github.com/aws-amplify/amplify-js/commit/b16ded3)) -## [1.0.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.7-unstable.0...@aws-amplify/ui@1.0.7) (2018-10-17) - - +## [1.0.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.7-unstable.0...@aws-amplify/ui@1.0.7) (2018-10-17) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.7-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.6-unstable.0...@aws-amplify/ui@1.0.7-unstable.0) (2018-10-05) - - +## [1.0.7-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.6-unstable.0...@aws-amplify/ui@1.0.7-unstable.0) (2018-10-05) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.6](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.6-unstable.0...@aws-amplify/ui@1.0.6) (2018-10-04) - - +## [1.0.6](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.6-unstable.0...@aws-amplify/ui@1.0.6) (2018-10-04) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.5-unstable.0...@aws-amplify/ui@1.0.6-unstable.0) (2018-10-03) - - +## [1.0.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.5-unstable.0...@aws-amplify/ui@1.0.6-unstable.0) (2018-10-03) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.5](https://github.com/powerful23/aws-amplify/compare/@aws-amplify/ui@1.0.5-unstable.0...@aws-amplify/ui@1.0.5) (2018-10-03) - - +## [1.0.5](https://github.com/powerful23/aws-amplify/compare/@aws-amplify/ui@1.0.5-unstable.0...@aws-amplify/ui@1.0.5) (2018-10-03) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.4...@aws-amplify/ui@1.0.5-unstable.0) (2018-10-02) - - +## [1.0.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.4...@aws-amplify/ui@1.0.5-unstable.0) (2018-10-02) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.4-unstable.1...@aws-amplify/ui@1.0.4) (2018-09-27) - - +## [1.0.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.4-unstable.1...@aws-amplify/ui@1.0.4) (2018-09-27) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.4-unstable.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.4-unstable.0...@aws-amplify/ui@1.0.4-unstable.1) (2018-09-26) - - +## [1.0.4-unstable.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.4-unstable.0...@aws-amplify/ui@1.0.4-unstable.1) (2018-09-26) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.4-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.3...@aws-amplify/ui@1.0.4-unstable.0) (2018-09-26) - - +## [1.0.4-unstable.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.3...@aws-amplify/ui@1.0.4-unstable.0) (2018-09-26) **Note:** Version bump only for package @aws-amplify/ui -## [1.0.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.2...@aws-amplify/ui@1.0.3) (2018-09-17) +## [1.0.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.2...@aws-amplify/ui@1.0.3) (2018-09-17) ### Bug Fixes -* **aws-amplify-angular:** authState visibility issues on initial load ([#1657](https://github.com/aws-amplify/amplify-js/issues/1657)) ([50611fe](https://github.com/aws-amplify/amplify-js/commit/50611fe)) -* **aws-amplify-angular:** responsive styles for components ([650ddf2](https://github.com/aws-amplify/amplify-js/commit/650ddf2)) -* **aws-amplify-angular:** updates to responsive ui ([a036278](https://github.com/aws-amplify/amplify-js/commit/a036278)) - - - +- **aws-amplify-angular:** authState visibility issues on initial load ([#1657](https://github.com/aws-amplify/amplify-js/issues/1657)) ([50611fe](https://github.com/aws-amplify/amplify-js/commit/50611fe)) +- **aws-amplify-angular:** responsive styles for components ([650ddf2](https://github.com/aws-amplify/amplify-js/commit/650ddf2)) +- **aws-amplify-angular:** updates to responsive ui ([a036278](https://github.com/aws-amplify/amplify-js/commit/a036278)) -## [1.0.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.1-unstable.0...@aws-amplify/ui@1.0.2) (2018-08-28) - - +## [1.0.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui@1.0.1-unstable.0...@aws-amplify/ui@1.0.2) (2018-08-28) **Note:** Version bump only for package @aws-amplify/ui -## 1.0.1-unstable.0 (2018-08-28) +## 1.0.1-unstable.0 (2018-08-28) -* Amplify ui migration (#1517) ([41d3184](https://github.com/aws-amplify/amplify-js/commit/41d3184)), closes [#1517](https://github.com/aws-amplify/amplify-js/issues/1517) - +- Amplify ui migration (#1517) ([41d3184](https://github.com/aws-amplify/amplify-js/commit/41d3184)), closes [#1517](https://github.com/aws-amplify/amplify-js/issues/1517) ### BREAKING CHANGES -* UI Components +- UI Components diff --git a/packages/amplify-ui/postcss.config.js b/packages/amplify-ui/postcss.config.js index 88752c6cb06..aeefe5ad6fd 100644 --- a/packages/amplify-ui/postcss.config.js +++ b/packages/amplify-ui/postcss.config.js @@ -1,5 +1,3 @@ module.exports = { - plugins: [ - require('autoprefixer') - ] -} + plugins: [require('autoprefixer')], +}; diff --git a/packages/amplify-ui/src/index.ts b/packages/amplify-ui/src/index.ts index b7f2e4ed01a..b1fd7c4285c 100644 --- a/packages/amplify-ui/src/index.ts +++ b/packages/amplify-ui/src/index.ts @@ -1,4 +1,3 @@ - /* * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. * @@ -23,4 +22,4 @@ export * from './SelectInput.css'; export * from './Strike.css'; export * from './Toast.css'; export * from './Totp.css'; -export * from './XR.css'; \ No newline at end of file +export * from './XR.css'; diff --git a/packages/amplify-ui/webpack.config.js b/packages/amplify-ui/webpack.config.js index 61a4854cc2b..a85d45f41a8 100644 --- a/packages/amplify-ui/webpack.config.js +++ b/packages/amplify-ui/webpack.config.js @@ -1,55 +1,63 @@ -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { - entry: { - "aws-amplify-ui": "./src/index.ts", - "aws-amplify-ui.min": "./src/index.ts" - }, - output: { - filename: "[name].js", - path: __dirname + "/dist", - library: "aws_amplify_ui", - libraryTarget: "umd", - umdNamedDefine: true, - globalObject: 'this', - devtoolModuleFilenameTemplate: require("../aws-amplify/webpack-utils") - .devtoolModuleFilenameTemplate - }, - // Enable sourcemaps for debugging webpack's output. - devtool: "source-map", - resolve: { - extensions: [".tsx", ".ts", ".js", ".css"] - }, + entry: { + 'aws-amplify-ui': './src/index.ts', + 'aws-amplify-ui.min': './src/index.ts', + }, + output: { + filename: '[name].js', + path: __dirname + '/dist', + library: 'aws_amplify_ui', + libraryTarget: 'umd', + umdNamedDefine: true, + globalObject: 'this', + devtoolModuleFilenameTemplate: require('../aws-amplify/webpack-utils') + .devtoolModuleFilenameTemplate, + }, + // Enable sourcemaps for debugging webpack's output. + devtool: 'source-map', + resolve: { + extensions: ['.tsx', '.ts', '.js', '.css'], + }, - mode: process.env.NODE_ENV || "production", + mode: process.env.NODE_ENV || 'production', - module: { - rules: [ - { test: /\.jsx?$/, use: "ts-loader", exclude: /node_modules/ }, - { test: /\.tsx?$/, use: "ts-loader", exclude: /node_modules/ }, - { - test: /\.css$/, - use: [ - { - loader: MiniCssExtractPlugin.loader, - options: { - hmr: process.env.NODE_ENV === "development" - } - }, - { loader: "dts-css-modules-loader", options: { banner: "// AUTOMATICALLY GENERATED - DO NOT EDIT", namedExport: true } }, - { - loader: "css-loader", - options: { - modules: true, - importLoaders: 1, - localIdentName: "[name]__[local]___[hash:base64:5]" - } - }, - "postcss-loader" - ] - } - ] - }, + module: { + rules: [ + { test: /\.jsx?$/, use: 'ts-loader', exclude: /node_modules/ }, + { test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/ }, + { + test: /\.css$/, + use: [ + { + loader: MiniCssExtractPlugin.loader, + options: { + hmr: process.env.NODE_ENV === 'development', + }, + }, + { + loader: 'dts-css-modules-loader', + options: { + banner: '// AUTOMATICALLY GENERATED - DO NOT EDIT', + namedExport: true, + }, + }, + { + loader: 'css-loader', + options: { + modules: true, + importLoaders: 1, + localIdentName: '[name]__[local]___[hash:base64:5]', + }, + }, + 'postcss-loader', + ], + }, + ], + }, - plugins: [new MiniCssExtractPlugin({ filename: "style.css", allChunks: true })] + plugins: [ + new MiniCssExtractPlugin({ filename: 'style.css', allChunks: true }), + ], }; diff --git a/packages/analytics/CHANGELOG.md b/packages/analytics/CHANGELOG.md index 8c9cd92f3ad..d644bd9a25f 100644 --- a/packages/analytics/CHANGELOG.md +++ b/packages/analytics/CHANGELOG.md @@ -7,933 +7,682 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package @aws-amplify/analytics - - - - ## [1.2.24](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.23...@aws-amplify/analytics@1.2.24) (2019-09-04) **Note:** Version bump only for package @aws-amplify/analytics - - - - ## [1.2.23](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.22...@aws-amplify/analytics@1.2.23) (2019-08-05) **Note:** Version bump only for package @aws-amplify/analytics - - - - ## [1.2.22](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.21...@aws-amplify/analytics@1.2.22) (2019-07-31) **Note:** Version bump only for package @aws-amplify/analytics - - - - ## [1.2.21](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.20...@aws-amplify/analytics@1.2.21) (2019-07-30) **Note:** Version bump only for package @aws-amplify/analytics - - - - ## [1.2.20](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.18...@aws-amplify/analytics@1.2.20) (2019-07-18) **Note:** Version bump only for package @aws-amplify/analytics - - - - -## [1.2.19-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.18...@aws-amplify/analytics@1.2.19-unstable.0) (2019-07-12) +## [1.2.19-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.18...@aws-amplify/analytics@1.2.19-unstable.0) (2019-07-12) ### Bug Fixes -* **@aws-amplify/analytics:** use startsWith to filter the updateEndpoint error message ([#3589](https://github.com/aws/aws-amplify/issues/3589)) ([0bd68f9](https://github.com/aws/aws-amplify/commit/0bd68f9)) - - - +- **@aws-amplify/analytics:** use startsWith to filter the updateEndpoint error message ([#3589](https://github.com/aws/aws-amplify/issues/3589)) ([0bd68f9](https://github.com/aws/aws-amplify/commit/0bd68f9)) -## [1.2.18](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.18-unstable.1...@aws-amplify/analytics@1.2.18) (2019-07-09) - - +## [1.2.18](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.18-unstable.1...@aws-amplify/analytics@1.2.18) (2019-07-09) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.18-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.18-unstable.0...@aws-amplify/analytics@1.2.18-unstable.1) (2019-07-09) +## [1.2.18-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.18-unstable.0...@aws-amplify/analytics@1.2.18-unstable.1) (2019-07-09) ### Bug Fixes -* **@aws-amplify/analytics:** do not send events when analytics modules not configured ([#3614](https://github.com/aws/aws-amplify/issues/3614)) ([82e6f28](https://github.com/aws/aws-amplify/commit/82e6f28)) - - - +- **@aws-amplify/analytics:** do not send events when analytics modules not configured ([#3614](https://github.com/aws/aws-amplify/issues/3614)) ([82e6f28](https://github.com/aws/aws-amplify/commit/82e6f28)) -## [1.2.18-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.17...@aws-amplify/analytics@1.2.18-unstable.0) (2019-06-18) - - +## [1.2.18-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.17...@aws-amplify/analytics@1.2.18-unstable.0) (2019-06-18) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.17](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.17-unstable.3...@aws-amplify/analytics@1.2.17) (2019-06-17) - - +## [1.2.17](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.17-unstable.3...@aws-amplify/analytics@1.2.17) (2019-06-17) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.17-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.17-unstable.2...@aws-amplify/analytics@1.2.17-unstable.3) (2019-06-14) - - +## [1.2.17-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.17-unstable.2...@aws-amplify/analytics@1.2.17-unstable.3) (2019-06-14) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.17-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.17-unstable.1...@aws-amplify/analytics@1.2.17-unstable.2) (2019-06-07) +## [1.2.17-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.17-unstable.1...@aws-amplify/analytics@1.2.17-unstable.2) (2019-06-07) ### Bug Fixes -* **@aws-amplify/analytics:** resolve/reject correctly when calling reocrd ([c3eb6cc](https://github.com/aws/aws-amplify/commit/c3eb6cc)) - - - +- **@aws-amplify/analytics:** resolve/reject correctly when calling reocrd ([c3eb6cc](https://github.com/aws/aws-amplify/commit/c3eb6cc)) -## [1.2.17-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.16...@aws-amplify/analytics@1.2.17-unstable.1) (2019-05-24) +## [1.2.17-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.16...@aws-amplify/analytics@1.2.17-unstable.1) (2019-05-24) ### Bug Fixes -* **@aws-amplify/analytics:** manual version bump ([b347e0d](https://github.com/aws/aws-amplify/commit/b347e0d)) - - - +- **@aws-amplify/analytics:** manual version bump ([b347e0d](https://github.com/aws/aws-amplify/commit/b347e0d)) -## [1.2.16](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.16-unstable.0...@aws-amplify/analytics@1.2.16) (2019-05-14) - - +## [1.2.16](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.16-unstable.0...@aws-amplify/analytics@1.2.16) (2019-05-14) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.16-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.15...@aws-amplify/analytics@1.2.16-unstable.0) (2019-05-13) - - +## [1.2.16-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.15...@aws-amplify/analytics@1.2.16-unstable.0) (2019-05-13) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.15-unstable.3...@aws-amplify/analytics@1.2.15) (2019-05-06) - - +## [1.2.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.15-unstable.3...@aws-amplify/analytics@1.2.15) (2019-05-06) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.15-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.15-unstable.2...@aws-amplify/analytics@1.2.15-unstable.3) (2019-05-06) - - +## [1.2.15-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.15-unstable.2...@aws-amplify/analytics@1.2.15-unstable.3) (2019-05-06) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.15-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.15-unstable.1...@aws-amplify/analytics@1.2.15-unstable.2) (2019-04-22) +## [1.2.15-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.15-unstable.1...@aws-amplify/analytics@1.2.15-unstable.2) (2019-04-22) ### Bug Fixes -* **@aws-amplify/analytics:** prevent sending reqeusts simultaneously if endpoint is not generated yet ([8a7d7cc](https://github.com/aws/aws-amplify/commit/8a7d7cc)) - - - +- **@aws-amplify/analytics:** prevent sending reqeusts simultaneously if endpoint is not generated yet ([8a7d7cc](https://github.com/aws/aws-amplify/commit/8a7d7cc)) -## [1.2.15-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.15-unstable.0...@aws-amplify/analytics@1.2.15-unstable.1) (2019-04-17) - - +## [1.2.15-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.15-unstable.0...@aws-amplify/analytics@1.2.15-unstable.1) (2019-04-17) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.15-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.14...@aws-amplify/analytics@1.2.15-unstable.0) (2019-04-12) - - +## [1.2.15-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.14...@aws-amplify/analytics@1.2.15-unstable.0) (2019-04-12) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.14-unstable.0...@aws-amplify/analytics@1.2.14) (2019-04-09) - - +## [1.2.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.14-unstable.0...@aws-amplify/analytics@1.2.14) (2019-04-09) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.14-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.13...@aws-amplify/analytics@1.2.14-unstable.0) (2019-04-05) - - +## [1.2.14-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.13...@aws-amplify/analytics@1.2.14-unstable.0) (2019-04-05) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.13-unstable.1...@aws-amplify/analytics@1.2.13) (2019-04-04) - - +## [1.2.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.13-unstable.1...@aws-amplify/analytics@1.2.13) (2019-04-04) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.13-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.13-unstable.0...@aws-amplify/analytics@1.2.13-unstable.1) (2019-04-04) - - +## [1.2.13-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.13-unstable.0...@aws-amplify/analytics@1.2.13-unstable.1) (2019-04-04) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.13-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.12...@aws-amplify/analytics@1.2.13-unstable.0) (2019-04-02) - - +## [1.2.13-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.12...@aws-amplify/analytics@1.2.13-unstable.0) (2019-04-02) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.12-unstable.3...@aws-amplify/analytics@1.2.12) (2019-03-28) - - +## [1.2.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.12-unstable.3...@aws-amplify/analytics@1.2.12) (2019-03-28) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.12-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.12-unstable.2...@aws-amplify/analytics@1.2.12-unstable.3) (2019-03-28) +## [1.2.12-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.12-unstable.2...@aws-amplify/analytics@1.2.12-unstable.3) (2019-03-28) ### Features -* **core:** Hub refactor and tests ([7ac5bcf](https://github.com/aws/aws-amplify/commit/7ac5bcf)) - - - +- **core:** Hub refactor and tests ([7ac5bcf](https://github.com/aws/aws-amplify/commit/7ac5bcf)) -## [1.2.12-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.12-unstable.1...@aws-amplify/analytics@1.2.12-unstable.2) (2019-03-22) - - +## [1.2.12-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.12-unstable.1...@aws-amplify/analytics@1.2.12-unstable.2) (2019-03-22) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.12-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.12-unstable.0...@aws-amplify/analytics@1.2.12-unstable.1) (2019-03-08) +## [1.2.12-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.12-unstable.0...@aws-amplify/analytics@1.2.12-unstable.1) (2019-03-08) ### Bug Fixes -* **@aws-amplify/analytics:** use the correct user id when unlinking endpoints ([acb955f](https://github.com/aws/aws-amplify/commit/acb955f)) - - - +- **@aws-amplify/analytics:** use the correct user id when unlinking endpoints ([acb955f](https://github.com/aws/aws-amplify/commit/acb955f)) -## [1.2.12-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11...@aws-amplify/analytics@1.2.12-unstable.0) (2019-03-07) - - +## [1.2.12-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11...@aws-amplify/analytics@1.2.12-unstable.0) (2019-03-07) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.7...@aws-amplify/analytics@1.2.11) (2019-03-04) - - +## [1.2.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.7...@aws-amplify/analytics@1.2.11) (2019-03-04) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.11-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.6...@aws-amplify/analytics@1.2.11-unstable.7) (2019-03-04) - - +## [1.2.11-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.6...@aws-amplify/analytics@1.2.11-unstable.7) (2019-03-04) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.11-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.5...@aws-amplify/analytics@1.2.11-unstable.6) (2019-02-27) - - +## [1.2.11-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.5...@aws-amplify/analytics@1.2.11-unstable.6) (2019-02-27) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.11-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.4...@aws-amplify/analytics@1.2.11-unstable.5) (2019-02-27) - - +## [1.2.11-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.4...@aws-amplify/analytics@1.2.11-unstable.5) (2019-02-27) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.11-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.3...@aws-amplify/analytics@1.2.11-unstable.4) (2019-02-27) - - +## [1.2.11-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.3...@aws-amplify/analytics@1.2.11-unstable.4) (2019-02-27) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.11-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.2...@aws-amplify/analytics@1.2.11-unstable.3) (2019-02-20) - - +## [1.2.11-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.2...@aws-amplify/analytics@1.2.11-unstable.3) (2019-02-20) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.11-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.1...@aws-amplify/analytics@1.2.11-unstable.2) (2019-01-22) - - +## [1.2.11-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.1...@aws-amplify/analytics@1.2.11-unstable.2) (2019-01-22) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.11-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.0...@aws-amplify/analytics@1.2.11-unstable.1) (2019-01-10) - - +## [1.2.11-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.11-unstable.0...@aws-amplify/analytics@1.2.11-unstable.1) (2019-01-10) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.11-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.10...@aws-amplify/analytics@1.2.11-unstable.0) (2019-01-10) - - +## [1.2.11-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.10...@aws-amplify/analytics@1.2.11-unstable.0) (2019-01-10) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.10-unstable.0...@aws-amplify/analytics@1.2.10) (2019-01-10) +## [1.2.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.10-unstable.0...@aws-amplify/analytics@1.2.10) (2019-01-10) ### Bug Fixes -* **@aws-amplify/analytics:** fix the event name of session start/stop ([12f4e6f](https://github.com/aws/aws-amplify/commit/12f4e6f)) - - - +- **@aws-amplify/analytics:** fix the event name of session start/stop ([12f4e6f](https://github.com/aws/aws-amplify/commit/12f4e6f)) -## [1.2.10-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.9...@aws-amplify/analytics@1.2.10-unstable.0) (2018-12-26) - - +## [1.2.10-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.9...@aws-amplify/analytics@1.2.10-unstable.0) (2018-12-26) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.9-unstable.2...@aws-amplify/analytics@1.2.9) (2018-12-26) - - +## [1.2.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.9-unstable.2...@aws-amplify/analytics@1.2.9) (2018-12-26) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.9-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.9-unstable.1...@aws-amplify/analytics@1.2.9-unstable.2) (2018-12-24) +## [1.2.9-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.9-unstable.1...@aws-amplify/analytics@1.2.9-unstable.2) (2018-12-24) ### Bug Fixes -* **@aws-amplify/analytics:** unlink user id from endpoint when limit exceeds ([b2de140](https://github.com/aws/aws-amplify/commit/b2de140)) - - - +- **@aws-amplify/analytics:** unlink user id from endpoint when limit exceeds ([b2de140](https://github.com/aws/aws-amplify/commit/b2de140)) -## [1.2.9-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.9-unstable.0...@aws-amplify/analytics@1.2.9-unstable.1) (2018-12-24) +## [1.2.9-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.9-unstable.0...@aws-amplify/analytics@1.2.9-unstable.1) (2018-12-24) ### Bug Fixes -* **@aws-amplify/analytics:** clear timer when analytics is disabled ([5d1370d](https://github.com/aws/aws-amplify/commit/5d1370d)) - - - +- **@aws-amplify/analytics:** clear timer when analytics is disabled ([5d1370d](https://github.com/aws/aws-amplify/commit/5d1370d)) -## [1.2.9-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.8...@aws-amplify/analytics@1.2.9-unstable.0) (2018-12-22) - - +## [1.2.9-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.8...@aws-amplify/analytics@1.2.9-unstable.0) (2018-12-22) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.8-unstable.3...@aws-amplify/analytics@1.2.8) (2018-12-13) - - +## [1.2.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.8-unstable.3...@aws-amplify/analytics@1.2.8) (2018-12-13) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.8-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.8-unstable.2...@aws-amplify/analytics@1.2.8-unstable.3) (2018-12-13) +## [1.2.8-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.8-unstable.2...@aws-amplify/analytics@1.2.8-unstable.3) (2018-12-13) ### Bug Fixes -* **@aws-amplify/analytics:** fix the type definition ([34daec2](https://github.com/aws/aws-amplify/commit/34daec2)) - - - +- **@aws-amplify/analytics:** fix the type definition ([34daec2](https://github.com/aws/aws-amplify/commit/34daec2)) -## [1.2.8-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.8-unstable.1...@aws-amplify/analytics@1.2.8-unstable.2) (2018-12-12) +## [1.2.8-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.8-unstable.1...@aws-amplify/analytics@1.2.8-unstable.2) (2018-12-12) ### Bug Fixes -* **@aws-amplify/pushnotification:** send campaign open events when app is opend by notification ([d21d4fe](https://github.com/aws/aws-amplify/commit/d21d4fe)) - - - +- **@aws-amplify/pushnotification:** send campaign open events when app is opend by notification ([d21d4fe](https://github.com/aws/aws-amplify/commit/d21d4fe)) -## [1.2.8-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.8-unstable.0...@aws-amplify/analytics@1.2.8-unstable.1) (2018-12-10) +## [1.2.8-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.8-unstable.0...@aws-amplify/analytics@1.2.8-unstable.1) (2018-12-10) ### Bug Fixes -* **@aws-amplify/analytics:** generate endpoint id if not provided ([cca9d2f](https://github.com/aws/aws-amplify/commit/cca9d2f)) - - - +- **@aws-amplify/analytics:** generate endpoint id if not provided ([cca9d2f](https://github.com/aws/aws-amplify/commit/cca9d2f)) -## [1.2.8-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7...@aws-amplify/analytics@1.2.8-unstable.0) (2018-12-07) - - +## [1.2.8-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7...@aws-amplify/analytics@1.2.8-unstable.0) (2018-12-07) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.5...@aws-amplify/analytics@1.2.7) (2018-12-03) - - +## [1.2.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.5...@aws-amplify/analytics@1.2.7) (2018-12-03) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.7-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.4...@aws-amplify/analytics@1.2.7-unstable.5) (2018-11-29) +## [1.2.7-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.4...@aws-amplify/analytics@1.2.7-unstable.5) (2018-11-29) ### Bug Fixes -* **@aws-amplify/analytics:** avoid return statement in the beforeunload function ([2b6e95e](https://github.com/aws/aws-amplify/commit/2b6e95e)) - - - +- **@aws-amplify/analytics:** avoid return statement in the beforeunload function ([2b6e95e](https://github.com/aws/aws-amplify/commit/2b6e95e)) -## [1.2.7-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.3...@aws-amplify/analytics@1.2.7-unstable.4) (2018-11-27) - - +## [1.2.7-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.3...@aws-amplify/analytics@1.2.7-unstable.4) (2018-11-27) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.7-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.2...@aws-amplify/analytics@1.2.7-unstable.3) (2018-11-26) - - +## [1.2.7-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.2...@aws-amplify/analytics@1.2.7-unstable.3) (2018-11-26) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.7-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.1...@aws-amplify/analytics@1.2.7-unstable.2) (2018-11-20) - - +## [1.2.7-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.1...@aws-amplify/analytics@1.2.7-unstable.2) (2018-11-20) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.7-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.0...@aws-amplify/analytics@1.2.7-unstable.1) (2018-11-19) - - +## [1.2.7-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.7-unstable.0...@aws-amplify/analytics@1.2.7-unstable.1) (2018-11-19) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.7-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.6...@aws-amplify/analytics@1.2.7-unstable.0) (2018-11-15) - - +## [1.2.7-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.6...@aws-amplify/analytics@1.2.7-unstable.0) (2018-11-15) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.6-unstable.2...@aws-amplify/analytics@1.2.6) (2018-11-12) - - +## [1.2.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.6-unstable.2...@aws-amplify/analytics@1.2.6) (2018-11-12) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.6-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.6-unstable.1...@aws-amplify/analytics@1.2.6-unstable.2) (2018-11-09) - - +## [1.2.6-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.6-unstable.1...@aws-amplify/analytics@1.2.6-unstable.2) (2018-11-09) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.6-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.6-unstable.0...@aws-amplify/analytics@1.2.6-unstable.1) (2018-11-06) +## [1.2.6-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.6-unstable.0...@aws-amplify/analytics@1.2.6-unstable.1) (2018-11-06) ### Bug Fixes -* **@aws-amplify/analytics:** send session stop events when app turns into background/inactive ([e2e9b66](https://github.com/aws/aws-amplify/commit/e2e9b66)) - - - +- **@aws-amplify/analytics:** send session stop events when app turns into background/inactive ([e2e9b66](https://github.com/aws/aws-amplify/commit/e2e9b66)) -## [1.2.6-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.5...@aws-amplify/analytics@1.2.6-unstable.0) (2018-11-06) - - +## [1.2.6-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.5...@aws-amplify/analytics@1.2.6-unstable.0) (2018-11-06) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.5-unstable.1...@aws-amplify/analytics@1.2.5) (2018-11-01) - - +## [1.2.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.5-unstable.1...@aws-amplify/analytics@1.2.5) (2018-11-01) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.5-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.5-unstable.0...@aws-amplify/analytics@1.2.5-unstable.1) (2018-11-01) +## [1.2.5-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.5-unstable.0...@aws-amplify/analytics@1.2.5-unstable.1) (2018-11-01) ### Features -* **@aws-amplify/analytics:** allow users to fully configure pinpoint endpoint ([55727cf](https://github.com/aws/aws-amplify/commit/55727cf)) - - - +- **@aws-amplify/analytics:** allow users to fully configure pinpoint endpoint ([55727cf](https://github.com/aws/aws-amplify/commit/55727cf)) -## [1.2.5-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4...@aws-amplify/analytics@1.2.5-unstable.0) (2018-10-30) - - +## [1.2.5-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4...@aws-amplify/analytics@1.2.5-unstable.0) (2018-10-30) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4-unstable.4...@aws-amplify/analytics@1.2.4) (2018-10-17) - - +## [1.2.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4-unstable.4...@aws-amplify/analytics@1.2.4) (2018-10-17) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.4-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4-unstable.3...@aws-amplify/analytics@1.2.4-unstable.4) (2018-10-17) - - +## [1.2.4-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4-unstable.3...@aws-amplify/analytics@1.2.4-unstable.4) (2018-10-17) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.4-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4-unstable.2...@aws-amplify/analytics@1.2.4-unstable.3) (2018-10-16) - - +## [1.2.4-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4-unstable.2...@aws-amplify/analytics@1.2.4-unstable.3) (2018-10-16) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.4-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4-unstable.1...@aws-amplify/analytics@1.2.4-unstable.2) (2018-10-08) - - +## [1.2.4-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4-unstable.1...@aws-amplify/analytics@1.2.4-unstable.2) (2018-10-08) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.4-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4-unstable.0...@aws-amplify/analytics@1.2.4-unstable.1) (2018-10-05) - - +## [1.2.4-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.4-unstable.0...@aws-amplify/analytics@1.2.4-unstable.1) (2018-10-05) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.4-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.3-unstable.1...@aws-amplify/analytics@1.2.4-unstable.0) (2018-10-05) - - +## [1.2.4-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.3-unstable.1...@aws-amplify/analytics@1.2.4-unstable.0) (2018-10-05) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.3-unstable.1...@aws-amplify/analytics@1.2.3) (2018-10-04) - - +## [1.2.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.3-unstable.1...@aws-amplify/analytics@1.2.3) (2018-10-04) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.3-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.3-unstable.0...@aws-amplify/analytics@1.2.3-unstable.1) (2018-10-03) - - +## [1.2.3-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.3-unstable.0...@aws-amplify/analytics@1.2.3-unstable.1) (2018-10-03) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.3-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.2-unstable.2...@aws-amplify/analytics@1.2.3-unstable.0) (2018-10-03) - - +## [1.2.3-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.2-unstable.2...@aws-amplify/analytics@1.2.3-unstable.0) (2018-10-03) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.2-unstable.2...@aws-amplify/analytics@1.2.2) (2018-10-03) - - +## [1.2.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.2-unstable.2...@aws-amplify/analytics@1.2.2) (2018-10-03) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.2-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.2-unstable.1...@aws-amplify/analytics@1.2.2-unstable.2) (2018-10-01) - - +## [1.2.2-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.2-unstable.1...@aws-amplify/analytics@1.2.2-unstable.2) (2018-10-01) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.2-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.2-unstable.0...@aws-amplify/analytics@1.2.2-unstable.1) (2018-10-01) - - +## [1.2.2-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.2-unstable.0...@aws-amplify/analytics@1.2.2-unstable.1) (2018-10-01) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.1...@aws-amplify/analytics@1.2.2-unstable.0) (2018-09-28) - - +## [1.2.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.1...@aws-amplify/analytics@1.2.2-unstable.0) (2018-09-28) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.1-unstable.3...@aws-amplify/analytics@1.2.1) (2018-09-27) - - +## [1.2.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.1-unstable.3...@aws-amplify/analytics@1.2.1) (2018-09-27) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.1-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.1-unstable.2...@aws-amplify/analytics@1.2.1-unstable.3) (2018-09-26) +## [1.2.1-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.1-unstable.2...@aws-amplify/analytics@1.2.1-unstable.3) (2018-09-26) ### Bug Fixes -* **@aws-amplify/analytics:** Auto session tracking after Auth is configured ([ce31f57](https://github.com/aws/aws-amplify/commit/ce31f57)) - - - +- **@aws-amplify/analytics:** Auto session tracking after Auth is configured ([ce31f57](https://github.com/aws/aws-amplify/commit/ce31f57)) -## [1.2.1-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.1-unstable.1...@aws-amplify/analytics@1.2.1-unstable.2) (2018-09-26) - - +## [1.2.1-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.1-unstable.1...@aws-amplify/analytics@1.2.1-unstable.2) (2018-09-26) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.1-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.1-unstable.0...@aws-amplify/analytics@1.2.1-unstable.1) (2018-09-25) - - +## [1.2.1-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.1-unstable.0...@aws-amplify/analytics@1.2.1-unstable.1) (2018-09-25) **Note:** Version bump only for package @aws-amplify/analytics -## [1.2.1-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.0...@aws-amplify/analytics@1.2.1-unstable.0) (2018-09-22) - - +## [1.2.1-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.2.0...@aws-amplify/analytics@1.2.1-unstable.0) (2018-09-22) **Note:** Version bump only for package @aws-amplify/analytics -# [1.2.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.1.2-unstable.0...@aws-amplify/analytics@1.2.0) (2018-09-21) +# [1.2.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.1.2-unstable.0...@aws-amplify/analytics@1.2.0) (2018-09-21) ### Bug Fixes -* **@aws-amplify/analytics:** check the environment before running dom-utils ([4375b21](https://github.com/aws/aws-amplify/commit/4375b21)) - +- **@aws-amplify/analytics:** check the environment before running dom-utils ([4375b21](https://github.com/aws/aws-amplify/commit/4375b21)) ### Features -* **aws-amplify/analytics:** using Pinpoint New API ([f8e60c1](https://github.com/aws/aws-amplify/commit/f8e60c1)) - - - +- **aws-amplify/analytics:** using Pinpoint New API ([f8e60c1](https://github.com/aws/aws-amplify/commit/f8e60c1)) -## [1.1.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.1.0...@aws-amplify/analytics@1.1.2-unstable.0) (2018-09-21) - - +## [1.1.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.1.0...@aws-amplify/analytics@1.1.2-unstable.0) (2018-09-21) **Note:** Version bump only for package @aws-amplify/analytics -## [1.1.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.1.0...@aws-amplify/analytics@1.1.1) (2018-09-21) - - +## [1.1.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.1.0...@aws-amplify/analytics@1.1.1) (2018-09-21) **Note:** Version bump only for package @aws-amplify/analytics -# [1.1.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.9...@aws-amplify/analytics@1.1.0) (2018-09-17) +# [1.1.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.9...@aws-amplify/analytics@1.1.0) (2018-09-17) ### Features -* **@aws-amplify/analytics:** Analytics auto tracking ([585edf2](https://github.com/aws/aws-amplify/commit/585edf2)) - - - +- **@aws-amplify/analytics:** Analytics auto tracking ([585edf2](https://github.com/aws/aws-amplify/commit/585edf2)) -## [1.0.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.8...@aws-amplify/analytics@1.0.9) (2018-09-12) +## [1.0.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.8...@aws-amplify/analytics@1.0.9) (2018-09-12) ### Bug Fixes -* **aws-amplify:** update the version of aws-sdk to latest ([482402d](https://github.com/aws/aws-amplify/commit/482402d)) - - - +- **aws-amplify:** update the version of aws-sdk to latest ([482402d](https://github.com/aws/aws-amplify/commit/482402d)) -## [1.0.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.7...@aws-amplify/analytics@1.0.8) (2018-09-09) - - +## [1.0.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.7...@aws-amplify/analytics@1.0.8) (2018-09-09) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.8-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.7...@aws-amplify/analytics@1.0.8-unstable.1) (2018-08-30) - - +## [1.0.8-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.7...@aws-amplify/analytics@1.0.8-unstable.1) (2018-08-30) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.6-unstable.3...@aws-amplify/analytics@1.0.7) (2018-08-28) - - +## [1.0.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.6-unstable.3...@aws-amplify/analytics@1.0.7) (2018-08-28) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.6-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.6-unstable.2...@aws-amplify/analytics@1.0.6-unstable.3) (2018-08-27) +## [1.0.6-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.6-unstable.2...@aws-amplify/analytics@1.0.6-unstable.3) (2018-08-27) ### Bug Fixes -* **@aws-amplify/analytics:** abort recording events when lacking of application id or region ([b2b631b](https://github.com/aws/aws-amplify/commit/b2b631b)) - - - +- **@aws-amplify/analytics:** abort recording events when lacking of application id or region ([b2b631b](https://github.com/aws/aws-amplify/commit/b2b631b)) -## [1.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.6-unstable.1...@aws-amplify/analytics@1.0.6-unstable.2) (2018-08-21) - - +## [1.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.6-unstable.1...@aws-amplify/analytics@1.0.6-unstable.2) (2018-08-21) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.6-unstable.0...@aws-amplify/analytics@1.0.6-unstable.1) (2018-08-20) - - +## [1.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.6-unstable.0...@aws-amplify/analytics@1.0.6-unstable.1) (2018-08-20) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.5...@aws-amplify/analytics@1.0.6-unstable.0) (2018-08-19) +## [1.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.5...@aws-amplify/analytics@1.0.6-unstable.0) (2018-08-19) ### Bug Fixes -* **aws-amplify-angular:** Angular rollup ([#1441](https://github.com/aws/aws-amplify/issues/1441)) ([eb84e01](https://github.com/aws/aws-amplify/commit/eb84e01)) - - - +- **aws-amplify-angular:** Angular rollup ([#1441](https://github.com/aws/aws-amplify/issues/1441)) ([eb84e01](https://github.com/aws/aws-amplify/commit/eb84e01)) -## [1.0.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.5-unstable.0...@aws-amplify/analytics@1.0.5) (2018-08-14) - - +## [1.0.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.5-unstable.0...@aws-amplify/analytics@1.0.5) (2018-08-14) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.4...@aws-amplify/analytics@1.0.5-unstable.0) (2018-08-09) - - +## [1.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.4...@aws-amplify/analytics@1.0.5-unstable.0) (2018-08-09) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.3-unstable.1...@aws-amplify/analytics@1.0.4) (2018-08-06) - - +## [1.0.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.3-unstable.1...@aws-amplify/analytics@1.0.4) (2018-08-06) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.3-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.3...@aws-amplify/analytics@1.0.3-unstable.1) (2018-08-06) - - +## [1.0.3-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.3...@aws-amplify/analytics@1.0.3-unstable.1) (2018-08-06) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.3-unstable.0...@aws-amplify/analytics@1.0.3) (2018-07-28) - - +## [1.0.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.3-unstable.0...@aws-amplify/analytics@1.0.3) (2018-07-28) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.2...@aws-amplify/analytics@1.0.3-unstable.0) (2018-07-26) - - +## [1.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.2...@aws-amplify/analytics@1.0.3-unstable.0) (2018-07-26) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.2-unstable.0...@aws-amplify/analytics@1.0.2) (2018-07-19) - - +## [1.0.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.2-unstable.0...@aws-amplify/analytics@1.0.2) (2018-07-19) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.1...@aws-amplify/analytics@1.0.2-unstable.0) (2018-07-19) - - +## [1.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.1...@aws-amplify/analytics@1.0.2-unstable.0) (2018-07-19) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.1-unstable.2...@aws-amplify/analytics@1.0.1) (2018-07-18) - - +## [1.0.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.1-unstable.2...@aws-amplify/analytics@1.0.1) (2018-07-18) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.1-unstable.1...@aws-amplify/analytics@1.0.1-unstable.2) (2018-07-18) - - +## [1.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.1-unstable.1...@aws-amplify/analytics@1.0.1-unstable.2) (2018-07-18) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.1...@aws-amplify/analytics@1.0.1-unstable.1) (2018-07-18) - - +## [1.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.1...@aws-amplify/analytics@1.0.1-unstable.1) (2018-07-18) **Note:** Version bump only for package @aws-amplify/analytics -## [1.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.1...@aws-amplify/analytics@1.0.1-unstable.0) (2018-07-18) - - +## [1.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/analytics@1.0.1...@aws-amplify/analytics@1.0.1-unstable.0) (2018-07-18) **Note:** Version bump only for package @aws-amplify/analytics -## 0.1.1-unstable.0 (2018-06-27) - - +## 0.1.1-unstable.0 (2018-06-27) **Note:** Version bump only for package @aws-amplify/analytics diff --git a/packages/analytics/__tests__/Analytics-unit-test.ts b/packages/analytics/__tests__/Analytics-unit-test.ts index c5a0d995564..0f790a8a72a 100644 --- a/packages/analytics/__tests__/Analytics-unit-test.ts +++ b/packages/analytics/__tests__/Analytics-unit-test.ts @@ -1,188 +1,210 @@ jest.mock('../src/vendor/dom-utils', () => { - return { - delegate: jest.fn() - } + return { + delegate: jest.fn(), + }; }); -import { AWS, ClientDevice, Parser, ConsoleLogger as Logger, Credentials } from '@aws-amplify/core'; +import { + AWS, + ClientDevice, + Parser, + ConsoleLogger as Logger, + Credentials, +} from '@aws-amplify/core'; import { AnalyticsOptions, EventAttributes, EventMetrics } from '../src/types'; -import { default as Analytics } from "../src/Analytics"; +import { default as Analytics } from '../src/Analytics'; import AWSAnalyticsProvider from '../src/Providers/AWSPinpointProvider'; const options: AnalyticsOptions = { - appId: 'appId', - platform: 'platform', - clientId: 'clientId', - region: 'region' + appId: 'appId', + platform: 'platform', + clientId: 'clientId', + region: 'region', }; const credentials = { - accessKeyId: 'accessKeyId', - sessionToken: 'sessionToken', - secretAccessKey: 'secretAccessKey', - identityId: 'identityId', - authenticated: true -} + accessKeyId: 'accessKeyId', + sessionToken: 'sessionToken', + secretAccessKey: 'secretAccessKey', + identityId: 'identityId', + authenticated: true, +}; jest.useFakeTimers(); -const record_spyon = jest.spyOn(AWSAnalyticsProvider.prototype, 'record').mockImplementation((params, handlers) => { - return handlers.resolve(); -}); - -describe("Analytics test", () => { - describe('configure test', () => { - test('happy case with default parser', () => { - const analytics = new Analytics(); - const spyon = jest.spyOn(ClientDevice, 'clientInfo').mockImplementationOnce(() => { - return 'clientInfo'; - }); - const spyon2 = jest.spyOn(Parser, 'parseMobilehubConfig').mockImplementationOnce(() => { - return { - Analytics: { - AWSPinpoint: { - appId: 'appId' - } - } - } - }); - const spyon3 = jest.spyOn(AWSAnalyticsProvider.prototype, 'configure').mockImplementationOnce(() => { return; }); - - expect(analytics.configure({attr: 'attr'})).toEqual({ AWSPinpoint: {appId: 'appId'}, attr: 'attr', "autoSessionRecord": true}); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - }); - }); - - describe('startSession test', () => { - test('happy case', async () => { - const analytics = new Analytics(); - const provider = new AWSAnalyticsProvider(); - analytics.addPluggable(provider); - analytics.configure({mock: "value"}); - - await analytics.startSession(); - expect(record_spyon).toBeCalled(); - }); - test('analytics not configured', async () => { - const analytics = new Analytics(); - - try { - await analytics.startSession(); - } catch (e) { - expect(e.message).toBe('Analytics has not been configured'); - } - expect.assertions(1); - }); - }); - - describe('stopSession test', () => { - test('happy case', async () => { - const analytics = new Analytics(); - const provider = new AWSAnalyticsProvider(); - analytics.addPluggable(provider); - analytics.configure({mock: "value"}); - - await analytics.stopSession(); - expect(record_spyon).toBeCalled(); - }); - test('analytics not configured', async () => { - const analytics = new Analytics(); - - try { - await analytics.stopSession(); - } catch (e) { - expect(e.message).toBe('Analytics has not been configured'); - } - expect.assertions(1); - }); - }); - - describe('record test', () => { - test('happy case', async () => { - const analytics = new Analytics(); - const provider = new AWSAnalyticsProvider(); - analytics.addPluggable(provider); - analytics.configure({mock: "value"}); - - await analytics.record({ - name: 'event', - attributes: 'attributes', - metrics: 'metrics' - }); - expect(record_spyon).toBeCalled(); - }); - test('analytics not configured', async () => { - const analytics = new Analytics(); - - try { - await analytics.record({}); - } catch (e) { - expect(e.message).toBe('Analytics has not been configured'); - } - expect.assertions(1); - }); - }); - - describe('updateEndpoint test', () => { - test('happy case', async () => { - const analytics = new Analytics(); - const provider = new AWSAnalyticsProvider(); - analytics.addPluggable(provider); - analytics.configure({mock: "value"}); - - await analytics.updateEndpoint({ - UserId: 'id' - }); - expect(record_spyon).toBeCalled(); - }); - test('analytics not configured', async () => { - const analytics = new Analytics(); - - try { - await analytics.updateEndpoint({}); - } catch (e) { - expect(e.message).toBe('Analytics has not been configured'); - } - expect.assertions(1); - }); - }); - - describe('analytics turn on/off test', () => { - test('disable test', () => { - const analytics = new Analytics(); - analytics.disable(); - }); - - test('enable test', () => { - const analytics = new Analytics(); - analytics.enable(); - }); - }); - - describe('getPluggable test', () => { - test('happy case', () => { - const analytics = new Analytics(); - - const provider = new AWSAnalyticsProvider(); - analytics.addPluggable(provider); - - expect(analytics.getPluggable(provider.getProviderName())).toBeInstanceOf(AWSAnalyticsProvider); - }); - }); - - describe('removePluggable test', () => { - test('happy case', () => { - const analytics = new Analytics(); - - const provider = new AWSAnalyticsProvider(); - analytics.addPluggable(provider); - - analytics.removePluggable(provider.getProviderName()); - - expect(analytics.getPluggable(provider.getProviderName())).toBeNull(); - }); - }); +const record_spyon = jest + .spyOn(AWSAnalyticsProvider.prototype, 'record') + .mockImplementation((params, handlers) => { + return handlers.resolve(); + }); + +describe('Analytics test', () => { + describe('configure test', () => { + test('happy case with default parser', () => { + const analytics = new Analytics(); + const spyon = jest + .spyOn(ClientDevice, 'clientInfo') + .mockImplementationOnce(() => { + return 'clientInfo'; + }); + const spyon2 = jest + .spyOn(Parser, 'parseMobilehubConfig') + .mockImplementationOnce(() => { + return { + Analytics: { + AWSPinpoint: { + appId: 'appId', + }, + }, + }; + }); + const spyon3 = jest + .spyOn(AWSAnalyticsProvider.prototype, 'configure') + .mockImplementationOnce(() => { + return; + }); + + expect(analytics.configure({ attr: 'attr' })).toEqual({ + AWSPinpoint: { appId: 'appId' }, + attr: 'attr', + autoSessionRecord: true, + }); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + }); + }); + + describe('startSession test', () => { + test('happy case', async () => { + const analytics = new Analytics(); + const provider = new AWSAnalyticsProvider(); + analytics.addPluggable(provider); + analytics.configure({ mock: 'value' }); + + await analytics.startSession(); + expect(record_spyon).toBeCalled(); + }); + test('analytics not configured', async () => { + const analytics = new Analytics(); + + try { + await analytics.startSession(); + } catch (e) { + expect(e.message).toBe('Analytics has not been configured'); + } + expect.assertions(1); + }); + }); + + describe('stopSession test', () => { + test('happy case', async () => { + const analytics = new Analytics(); + const provider = new AWSAnalyticsProvider(); + analytics.addPluggable(provider); + analytics.configure({ mock: 'value' }); + + await analytics.stopSession(); + expect(record_spyon).toBeCalled(); + }); + test('analytics not configured', async () => { + const analytics = new Analytics(); + + try { + await analytics.stopSession(); + } catch (e) { + expect(e.message).toBe('Analytics has not been configured'); + } + expect.assertions(1); + }); + }); + + describe('record test', () => { + test('happy case', async () => { + const analytics = new Analytics(); + const provider = new AWSAnalyticsProvider(); + analytics.addPluggable(provider); + analytics.configure({ mock: 'value' }); + + await analytics.record({ + name: 'event', + attributes: 'attributes', + metrics: 'metrics', + }); + expect(record_spyon).toBeCalled(); + }); + test('analytics not configured', async () => { + const analytics = new Analytics(); + + try { + await analytics.record({}); + } catch (e) { + expect(e.message).toBe('Analytics has not been configured'); + } + expect.assertions(1); + }); + }); + + describe('updateEndpoint test', () => { + test('happy case', async () => { + const analytics = new Analytics(); + const provider = new AWSAnalyticsProvider(); + analytics.addPluggable(provider); + analytics.configure({ mock: 'value' }); + + await analytics.updateEndpoint({ + UserId: 'id', + }); + expect(record_spyon).toBeCalled(); + }); + test('analytics not configured', async () => { + const analytics = new Analytics(); + + try { + await analytics.updateEndpoint({}); + } catch (e) { + expect(e.message).toBe('Analytics has not been configured'); + } + expect.assertions(1); + }); + }); + + describe('analytics turn on/off test', () => { + test('disable test', () => { + const analytics = new Analytics(); + analytics.disable(); + }); + + test('enable test', () => { + const analytics = new Analytics(); + analytics.enable(); + }); + }); + + describe('getPluggable test', () => { + test('happy case', () => { + const analytics = new Analytics(); + + const provider = new AWSAnalyticsProvider(); + analytics.addPluggable(provider); + + expect(analytics.getPluggable(provider.getProviderName())).toBeInstanceOf( + AWSAnalyticsProvider + ); + }); + }); + + describe('removePluggable test', () => { + test('happy case', () => { + const analytics = new Analytics(); + + const provider = new AWSAnalyticsProvider(); + analytics.addPluggable(provider); + + analytics.removePluggable(provider.getProviderName()); + + expect(analytics.getPluggable(provider.getProviderName())).toBeNull(); + }); + }); }); diff --git a/packages/analytics/__tests__/Providers/AWSKinesisProvider-unit-test.ts b/packages/analytics/__tests__/Providers/AWSKinesisProvider-unit-test.ts index 6f0c8aae67f..5b928284ce2 100644 --- a/packages/analytics/__tests__/Providers/AWSKinesisProvider-unit-test.ts +++ b/packages/analytics/__tests__/Providers/AWSKinesisProvider-unit-test.ts @@ -1,90 +1,104 @@ jest.mock('aws-sdk/clients/kinesis', () => { - const Kinesis = () => { - var kinesis = null; - return kinesis; - } + const Kinesis = () => { + var kinesis = null; + return kinesis; + }; - Kinesis.prototype.putRecords = (params, callback) => { - callback(null, 'data'); - } + Kinesis.prototype.putRecords = (params, callback) => { + callback(null, 'data'); + }; - return Kinesis; + return Kinesis; }); -import { Pinpoint, AWS, MobileAnalytics, JS, Credentials } from '@aws-amplify/core'; -import KinesisProvider from "../../src/Providers/AWSKinesisProvider"; +import { + Pinpoint, + AWS, + MobileAnalytics, + JS, + Credentials, +} from '@aws-amplify/core'; +import KinesisProvider from '../../src/Providers/AWSKinesisProvider'; jest.useFakeTimers(); const credentials = { - accessKeyId: 'accessKeyId', - sessionToken: 'sessionToken', - secretAccessKey: 'secretAccessKey', - identityId: 'identityId', - authenticated: true -} + accessKeyId: 'accessKeyId', + sessionToken: 'sessionToken', + secretAccessKey: 'secretAccessKey', + identityId: 'identityId', + authenticated: true, +}; -jest.useFakeTimers() +jest.useFakeTimers(); describe('kinesis provider test', () => { - describe('getCategory test', () => { - test('happy case', () => { - const analytics = new KinesisProvider(); - - expect(analytics.getCategory()).toBe('Analytics'); - }); - }); - - describe('getProviderName test', () => { - test('happy case', () => { - const analytics = new KinesisProvider(); - - expect(analytics.getProviderName()).toBe('AWSKinesis'); - }); - }); - - describe('configure test', () => { - test('happy case', () => { - const analytics = new KinesisProvider(); - - expect(analytics.configure({region: 'region1'})).toEqual({"bufferSize": 1000, "flushInterval": 5000, "flushSize": 100, "region": "region1", "resendLimit": 5}); - }); - }); - - describe('record test', () => { - test('record without credentials', async () => { - const analytics = new KinesisProvider(); - - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.reject('err'); - }); - - expect(await analytics.record('params')).toBe(false); - spyon.mockClear(); - }); - - test('record happy case', async () => { - const analytics = new KinesisProvider(); - - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - - await analytics.record({ - event: { - data: { - data: 'data' - }, - streamName: 'stream' - }, - config: {} - }); - - jest.advanceTimersByTime(6000); - - spyon.mockClear(); - }); - - }); -}); \ No newline at end of file + describe('getCategory test', () => { + test('happy case', () => { + const analytics = new KinesisProvider(); + + expect(analytics.getCategory()).toBe('Analytics'); + }); + }); + + describe('getProviderName test', () => { + test('happy case', () => { + const analytics = new KinesisProvider(); + + expect(analytics.getProviderName()).toBe('AWSKinesis'); + }); + }); + + describe('configure test', () => { + test('happy case', () => { + const analytics = new KinesisProvider(); + + expect(analytics.configure({ region: 'region1' })).toEqual({ + bufferSize: 1000, + flushInterval: 5000, + flushSize: 100, + region: 'region1', + resendLimit: 5, + }); + }); + }); + + describe('record test', () => { + test('record without credentials', async () => { + const analytics = new KinesisProvider(); + + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return Promise.reject('err'); + }); + + expect(await analytics.record('params')).toBe(false); + spyon.mockClear(); + }); + + test('record happy case', async () => { + const analytics = new KinesisProvider(); + + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + await analytics.record({ + event: { + data: { + data: 'data', + }, + streamName: 'stream', + }, + config: {}, + }); + + jest.advanceTimersByTime(6000); + + spyon.mockClear(); + }); + }); +}); diff --git a/packages/analytics/__tests__/Providers/AWSPinpointProvider-unit-test.ts b/packages/analytics/__tests__/Providers/AWSPinpointProvider-unit-test.ts index ef15c50529b..e37b27513cc 100644 --- a/packages/analytics/__tests__/Providers/AWSPinpointProvider-unit-test.ts +++ b/packages/analytics/__tests__/Providers/AWSPinpointProvider-unit-test.ts @@ -1,779 +1,795 @@ jest.mock('aws-sdk/clients/pinpoint', () => { - const Pinpoint = () => { - var pinpoint = null; - return pinpoint; - } - - Pinpoint.prototype.updateEndpoint = (params, callback) => { - callback(null, 'data'); - } - - Pinpoint.prototype.putEvents = (params) => { - return { - on(event, callback) { - callback(); - }, - send(callback) { - callback(null, { - EventsResponse: { - Results: { - 'endpointId' : { - EventsItemResponse :{ - 'uuid': { - Message: "Accepted", - StatusCode: 202 - } - } - } - } - } - }); - } - } - } - - return Pinpoint; + const Pinpoint = () => { + var pinpoint = null; + return pinpoint; + }; + + Pinpoint.prototype.updateEndpoint = (params, callback) => { + callback(null, 'data'); + }; + + Pinpoint.prototype.putEvents = params => { + return { + on(event, callback) { + callback(); + }, + send(callback) { + callback(null, { + EventsResponse: { + Results: { + endpointId: { + EventsItemResponse: { + uuid: { + Message: 'Accepted', + StatusCode: 202, + }, + }, + }, + }, + }, + }); + }, + }; + }; + + return Pinpoint; }); jest.mock('uuid', () => { - const mockfn = () => {return 'uuid'}; - return { v1: mockfn }; -}) + const mockfn = () => { + return 'uuid'; + }; + return { v1: mockfn }; +}); import { AWS, JS, Credentials, ClientDevice } from '@aws-amplify/core'; -import AnalyticsProvider from "../../src/Providers/AWSPinpointProvider"; +import AnalyticsProvider from '../../src/Providers/AWSPinpointProvider'; import { ConsoleLogger as Logger } from '@aws-amplify/core'; import Cache from '@aws-amplify/core'; import * as Pinpoint from 'aws-sdk/clients/pinpoint'; const endpointConfigure = { - address: 'configured', // The unique identifier for the recipient. For example, an address could be a device token, email address, or mobile phone number. - attributes: { - // Custom attributes that your app reports to Amazon Pinpoint. You can use these attributes as selection criteria when you create a segment. - hobbies: ['configured'], - }, - channelType: 'configured', // The channel type. Valid values: APNS, GCM - demographic: { - appVersion: 'configured', // The version of the application associated with the endpoint. - locale: 'configured', // The endpoint locale in the following format: The ISO 639-1 alpha-2 code, followed by an underscore, followed by an ISO 3166-1 alpha-2 value - make: 'configured', // The manufacturer of the endpoint device, such as Apple or Samsung. - model: 'configured', // The model name or number of the endpoint device, such as iPhone. - modelVersion: 'configured', // The model version of the endpoint device. - platform: 'configured', // The platform of the endpoint device, such as iOS or Android. - platformVersion: 'configured', // The platform version of the endpoint device. - timezone: 'configured' // The timezone of the endpoint. Specified as a tz database value, such as Americas/Los_Angeles. - }, - location: { - city: 'configured', // The city where the endpoint is located. - country: 'configured', // The two-letter code for the country or region of the endpoint. Specified as an ISO 3166-1 alpha-2 code, such as "US" for the United States. - latitude: 0, // The latitude of the endpoint location, rounded to one decimal place. - longitude: 0, // The longitude of the endpoint location, rounded to one decimal place. - postalCode: 'configured', // The postal code or zip code of the endpoint. - region: 'configured' // The region of the endpoint location. For example, in the United States, this corresponds to a state. - }, - metrics: { - // Custom metrics that your app reports to Amazon Pinpoint. - }, - /** Indicates whether a user has opted out of receiving messages with one of the following values: - * ALL - User has opted out of all messages. - * NONE - Users has not opted out and receives all messages. - */ - optOut: 'configured', - // Customized userId - userId: 'configured', - // User attributes - userAttributes: { - interests: ['configured'] - // ... - } + address: 'configured', // The unique identifier for the recipient. For example, an address could be a device token, email address, or mobile phone number. + attributes: { + // Custom attributes that your app reports to Amazon Pinpoint. You can use these attributes as selection criteria when you create a segment. + hobbies: ['configured'], + }, + channelType: 'configured', // The channel type. Valid values: APNS, GCM + demographic: { + appVersion: 'configured', // The version of the application associated with the endpoint. + locale: 'configured', // The endpoint locale in the following format: The ISO 639-1 alpha-2 code, followed by an underscore, followed by an ISO 3166-1 alpha-2 value + make: 'configured', // The manufacturer of the endpoint device, such as Apple or Samsung. + model: 'configured', // The model name or number of the endpoint device, such as iPhone. + modelVersion: 'configured', // The model version of the endpoint device. + platform: 'configured', // The platform of the endpoint device, such as iOS or Android. + platformVersion: 'configured', // The platform version of the endpoint device. + timezone: 'configured', // The timezone of the endpoint. Specified as a tz database value, such as Americas/Los_Angeles. + }, + location: { + city: 'configured', // The city where the endpoint is located. + country: 'configured', // The two-letter code for the country or region of the endpoint. Specified as an ISO 3166-1 alpha-2 code, such as "US" for the United States. + latitude: 0, // The latitude of the endpoint location, rounded to one decimal place. + longitude: 0, // The longitude of the endpoint location, rounded to one decimal place. + postalCode: 'configured', // The postal code or zip code of the endpoint. + region: 'configured', // The region of the endpoint location. For example, in the United States, this corresponds to a state. + }, + metrics: { + // Custom metrics that your app reports to Amazon Pinpoint. + }, + /** Indicates whether a user has opted out of receiving messages with one of the following values: + * ALL - User has opted out of all messages. + * NONE - Users has not opted out and receives all messages. + */ + optOut: 'configured', + // Customized userId + userId: 'configured', + // User attributes + userAttributes: { + interests: ['configured'], + // ... + }, }; const defaultEndpointConfigure = { - address: 'default', // The unique identifier for the recipient. For example, an address could be a device token, email address, or mobile phone number. - attributes: { - // Custom attributes that your app reports to Amazon Pinpoint. You can use these attributes as selection criteria when you create a segment. - hobbies: ['default'], - }, - channelType: 'default', // The channel type. Valid values: APNS, GCM - demographic: { - appVersion: 'default', // The version of the application associated with the endpoint. - locale: 'default', // The endpoint locale in the following format: The ISO 639-1 alpha-2 code, followed by an underscore, followed by an ISO 3166-1 alpha-2 value - make: 'default', // The manufacturer of the endpoint device, such as Apple or Samsung. - model: 'default', // The model name or number of the endpoint device, such as iPhone. - modelVersion: 'default', // The model version of the endpoint device. - platform: 'default', // The platform of the endpoint device, such as iOS or Android. - platformVersion: 'default', // The platform version of the endpoint device. - timezone: 'default' // The timezone of the endpoint. Specified as a tz database value, such as Americas/Los_Angeles. - }, - location: { - city: 'default', // The city where the endpoint is located. - country: 'default', // The two-letter code for the country or region of the endpoint. Specified as an ISO 3166-1 alpha-2 code, such as "US" for the United States. - latitude: 0, // The latitude of the endpoint location, rounded to one decimal place. - longitude: 0, // The longitude of the endpoint location, rounded to one decimal place. - postalCode: 'default', // The postal code or zip code of the endpoint. - region: 'default' // The region of the endpoint location. For example, in the United States, this corresponds to a state. - }, - metrics: { - // Custom metrics that your app reports to Amazon Pinpoint. - }, - /** Indicates whether a user has opted out of receiving messages with one of the following values: - * ALL - User has opted out of all messages. - * NONE - Users has not opted out and receives all messages. - */ - optOut: 'default', - // Customized userId - userId: 'default', - // User attributes - userAttributes: { - interests: ['default'] - // ... - } + address: 'default', // The unique identifier for the recipient. For example, an address could be a device token, email address, or mobile phone number. + attributes: { + // Custom attributes that your app reports to Amazon Pinpoint. You can use these attributes as selection criteria when you create a segment. + hobbies: ['default'], + }, + channelType: 'default', // The channel type. Valid values: APNS, GCM + demographic: { + appVersion: 'default', // The version of the application associated with the endpoint. + locale: 'default', // The endpoint locale in the following format: The ISO 639-1 alpha-2 code, followed by an underscore, followed by an ISO 3166-1 alpha-2 value + make: 'default', // The manufacturer of the endpoint device, such as Apple or Samsung. + model: 'default', // The model name or number of the endpoint device, such as iPhone. + modelVersion: 'default', // The model version of the endpoint device. + platform: 'default', // The platform of the endpoint device, such as iOS or Android. + platformVersion: 'default', // The platform version of the endpoint device. + timezone: 'default', // The timezone of the endpoint. Specified as a tz database value, such as Americas/Los_Angeles. + }, + location: { + city: 'default', // The city where the endpoint is located. + country: 'default', // The two-letter code for the country or region of the endpoint. Specified as an ISO 3166-1 alpha-2 code, such as "US" for the United States. + latitude: 0, // The latitude of the endpoint location, rounded to one decimal place. + longitude: 0, // The longitude of the endpoint location, rounded to one decimal place. + postalCode: 'default', // The postal code or zip code of the endpoint. + region: 'default', // The region of the endpoint location. For example, in the United States, this corresponds to a state. + }, + metrics: { + // Custom metrics that your app reports to Amazon Pinpoint. + }, + /** Indicates whether a user has opted out of receiving messages with one of the following values: + * ALL - User has opted out of all messages. + * NONE - Users has not opted out and receives all messages. + */ + optOut: 'default', + // Customized userId + userId: 'default', + // User attributes + userAttributes: { + interests: ['default'], + // ... + }, }; - const credentials = { - accessKeyId: 'accessKeyId', - sessionToken: 'sessionToken', - secretAccessKey: 'secretAccessKey', - identityId: 'identityId', - authenticated: true -} + accessKeyId: 'accessKeyId', + sessionToken: 'sessionToken', + secretAccessKey: 'secretAccessKey', + identityId: 'identityId', + authenticated: true, +}; const clientInfo = { - appVersion: '1.0', - make: 'make', - model: 'model', - version: '1.0.0', - platform: 'platform' -} + appVersion: '1.0', + make: 'make', + model: 'model', + version: '1.0.0', + platform: 'platform', +}; const options = { - appId: 'appId', - clientInfo: clientInfo, - credentials: credentials, - endpointId: 'endpointId', - region: 'region' -} + appId: 'appId', + clientInfo: clientInfo, + credentials: credentials, + endpointId: 'endpointId', + region: 'region', +}; const optionsWithDefaultEndpointConfigure = { - appId: 'appId', - clientInfo: clientInfo, - credentials: credentials, - endpointId: 'endpointId', - region: 'region', - endpoint: defaultEndpointConfigure -} + appId: 'appId', + clientInfo: clientInfo, + credentials: credentials, + endpointId: 'endpointId', + region: 'region', + endpoint: defaultEndpointConfigure, +}; const optionsWithClientContext = { - appId: 'appId', - clientInfo: clientInfo, - credentials: credentials, - endpointId: 'endpointId', - region: 'region', - clientContext: { - clientId: 'clientId', - appTitle: 'appTitle', - appVersionName: 'appVersionName', - appVersionCode: 'appVersionCode', - appPackageName: 'appPackageName', - platform: 'platform', - platformVersion: 'platformVersion', - model: 'model', - make: 'make', - locale: 'locale' - } + appId: 'appId', + clientInfo: clientInfo, + credentials: credentials, + endpointId: 'endpointId', + region: 'region', + clientContext: { + clientId: 'clientId', + appTitle: 'appTitle', + appVersionName: 'appVersionName', + appVersionCode: 'appVersionCode', + appPackageName: 'appPackageName', + platform: 'platform', + platformVersion: 'platformVersion', + model: 'model', + make: 'make', + locale: 'locale', + }, }; const optionsWithoutId = { - appId: undefined, - clientInfo: clientInfo, - credentials: credentials, - endpointId: 'endpointId', - region: 'region' + appId: undefined, + clientInfo: clientInfo, + credentials: credentials, + endpointId: 'endpointId', + region: 'region', }; const optionsWithoutRegion = { - appId: 'appId', - clientInfo: clientInfo, - credentials: credentials, - endpointId: 'endpointId', - region: undefined + appId: 'appId', + clientInfo: clientInfo, + credentials: credentials, + endpointId: 'endpointId', + region: undefined, }; let response = { - EventsResponse: { - Results: { - 'endpointId' : { - EventsItemResponse :{ - 'uuid': { - Message: "Accepted", - StatusCode: 202 - } - } - } - } - } -} - -const timeSpyOn = jest.spyOn(Date.prototype, 'getTime').mockImplementation(() => { - return 1526939075455; -}); + EventsResponse: { + Results: { + endpointId: { + EventsItemResponse: { + uuid: { + Message: 'Accepted', + StatusCode: 202, + }, + }, + }, + }, + }, +}; -const timeSpyOn2 = jest.spyOn(Date.prototype, 'toISOString').mockImplementation(() => { - return 'isoString'; -}); +const timeSpyOn = jest + .spyOn(Date.prototype, 'getTime') + .mockImplementation(() => { + return 1526939075455; + }); + +const timeSpyOn2 = jest + .spyOn(Date.prototype, 'toISOString') + .mockImplementation(() => { + return 'isoString'; + }); const timestamp = new Date().getTime(); jest.spyOn(ClientDevice, 'clientInfo').mockImplementation(() => { - return { - appVersion: 'clientInfoAppVersion', - make: 'clientInfoMake', - model: 'clientInfoModel', - version: 'clientInfoVersion', - platform: 'clientInfoPlatform' - } + return { + appVersion: 'clientInfoAppVersion', + make: 'clientInfoMake', + model: 'clientInfoModel', + version: 'clientInfoVersion', + platform: 'clientInfoPlatform', + }; }); let resolve = null; let reject = null; beforeEach(() => { - jest.useFakeTimers(); - resolve = jest.fn(); - reject = jest.fn(); + jest.useFakeTimers(); + resolve = jest.fn(); + reject = jest.fn(); }); -describe("AnalyticsProvider test", () => { - describe('getCategory test', () => { - test('happy case', () => { - const analytics = new AnalyticsProvider(); - - expect(analytics.getCategory()).toBe('Analytics'); - }); - }); - - describe('getProviderName test', () => { - test('happy case', () => { - const analytics = new AnalyticsProvider(); - - expect(analytics.getProviderName()).toBe('AWSPinpoint'); - }); - }); - - describe('configure test', () => { - test('happy case', () => { - const analytics = new AnalyticsProvider(); - - expect(analytics.configure({appId: 'appId'})).toEqual({"appId": "appId", "bufferSize": 1000, "flushInterval": 5000, "flushSize": 100, "resendLimit": 5}); - }); - }); - - describe('record test', () => { - test('record without credentials', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure(options); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.reject('err'); - }); - - await analytics.record('params', {resolve, reject}); - expect(reject).toBeCalled(); - spyon.mockClear(); - }); - - test('record without appId', async () => { - const analytics = new AnalyticsProvider(); - const { appId, ...rest } = options; - analytics.configure(rest); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - await analytics.record('params', {resolve, reject}); - expect(reject).toBeCalled(); - spyon.mockClear(); - }); - - test('record without region', async () => { - const analytics = new AnalyticsProvider(); - const { region, ...rest } = options; - analytics.configure(rest); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - await analytics.record('params', {resolve, reject}); - expect(reject).toBeCalled(); - spyon.mockClear(); - }); - - describe('record test', () => { - test('custom events', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure( - options - ); - const spyon = jest.spyOn(Pinpoint.prototype, 'putEvents').mockImplementationOnce((params) => { - return { - on(event, callback) { - return; - }, - send(callback) { - callback(null, response); - } - } - }); - - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - const params = {event: { name: 'custom event', immediate: true}}; - await analytics.record(params, {resolve, reject}); - - expect(spyon).toBeCalledWith({ - "ApplicationId": "appId", - "EventsRequest": { - "BatchItem": { - "endpointId": { - "Endpoint": { - }, - "Events": { - "uuid": { - "Attributes": undefined, - "EventType": "custom event", - "Metrics": undefined, - "Session": { - "Id": "uuid", - "StartTimestamp": "isoString" - }, - "Timestamp": "isoString" - } - } - } - } - } - }); - expect(resolve).toBeCalled(); - spyon.mockClear(); - }); - - test('custom event error', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure( - options - ); - - const spyon = jest.spyOn(Pinpoint.prototype, 'putEvents').mockImplementationOnce((params) => { - return { - on(event, callback) { - return; - }, - send(callback) { - callback('err', null); - } - } - }); - - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - - const params = {event: { name: 'custom event', immediate: true}}; - - await analytics.record(params, {resolve, reject}); - expect(reject).toBeCalled(); - spyon.mockClear(); - }); - }); - - describe('startsession test', () => { - test('happy case', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure( - options - ); - const spyon = jest.spyOn(Pinpoint.prototype, 'putEvents').mockImplementationOnce((params) => { - return { - on(event, callback) { - return; - }, - send(callback) { - callback(null, response); - } - } - }); - - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - const params = {event: { name: '_session.start', immediate: true}}; - await analytics.record(params, {resolve, reject}); - - expect(spyon).toBeCalledWith({ - "ApplicationId": "appId", - "EventsRequest": { - "BatchItem": { - "endpointId": { - "Endpoint": { - }, - "Events": { - "uuid": { - "Attributes": undefined, - "EventType": "_session.start", - "Metrics": undefined, - "Session": { - "Id": "uuid", - "StartTimestamp": "isoString" - }, - "Timestamp": "isoString" - } - } - } - } - } - }); - expect(resolve).toBeCalled(); - spyon.mockClear(); - }); - - test('session start error', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure( - options - ); - const spyon = jest.spyOn(Pinpoint.prototype, 'putEvents').mockImplementationOnce((params) => { - return { - on(event, callback) { - return; - }, - send(callback) { - callback('err', null); - } - } - }); - - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - - const params = {event: { name: '_session.start', immediate: true}}; - - await analytics.record(params, {resolve, reject}); - //expect(resolve).not.toBeCalled(); - expect(reject).toBeCalled(); - spyon.mockClear(); - }); - }); - - describe('stopSession test', () => { - test('happy case', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure( - options - ); - - const spyon = jest.spyOn(navigator, 'sendBeacon').mockImplementationOnce((params) => { - return true; - }); - - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - const params = {event: { name: '_session.stop', immediate: true}}; - await analytics.record(params, {resolve, reject}); - - const expectedUrl = "https://pinpoint.region.amazonaws.com/v1/apps/appId/events?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=accessKeyId%2FisoStrin%2Fregion%2Fmobiletargeting%2Faws4_request&X-Amz-Date=isoString&X-Amz-Security-Token=sessionToken&X-Amz-SignedHeaders=host&X-Amz-Signature=c43336d302010144ca492cc6f42d5545e0ef01c00bc71d99dc7597351f027810"; - const expectedData = JSON.stringify({ - "BatchItem": { - "endpointId": { - "Endpoint": {}, - "Events": { - "uuid": { - "EventType": "_session.stop", - "Timestamp": "isoString", - "Session": { - "Id": "uuid", - "Duration": 0, - "StartTimestamp": "isoString", - "StopTimestamp": "isoString" - } - } - } - } - } - }); - - expect(spyon).toBeCalledWith(expectedUrl, expectedData); - expect(resolve).toBeCalled(); - spyon.mockClear(); - }); - - test('session stop error', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure( - options - ); - const spyon = jest.spyOn(Pinpoint.prototype, 'putEvents').mockImplementationOnce((params) => { - return { - on(event, callback) { - return; - }, - send(callback) { - callback('err', null); - } - } - }); - - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - - const params = {event: { name: '_session.stop', immediate: true}}; - - await analytics.record(params, {resolve, reject}); - expect(reject).toBeCalled(); - spyon.mockClear(); - }); - }); - - describe('updateEndpoint test', () => { - test('happy case with default client info', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure(options); - const spyon = jest.spyOn(Pinpoint.prototype, 'updateEndpoint').mockImplementationOnce((params, callback) => { - callback(null, 'data'); - }); - - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - const params = {event: { name: '_update_endpoint', immediate: true}}; - await analytics.record(params, {resolve, reject}); - expect(spyon.mock.calls[0][0]).toEqual({ - "ApplicationId": "appId", - "EndpointId": "endpointId", - "EndpointRequest": { - "Attributes": {}, - "ChannelType": undefined, - "Demographic": { - "AppVersion": "clientInfoAppVersion", - "Make": "clientInfoMake", - "Model": "clientInfoModel", - "ModelVersion": "clientInfoVersion", - "Platform": "clientInfoPlatform" - }, - "EffectiveDate": "isoString", - "Location": {}, - "Metrics": {}, - "RequestId": "uuid", - "User": { - "UserAttributes": {}, - "UserId": "identityId" - } - } - }); - expect(resolve).toBeCalled(); - spyon.mockClear(); - }); - - test('happy case with client context provided', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure(optionsWithClientContext); - const spyon = jest.spyOn(Pinpoint.prototype, 'updateEndpoint').mockImplementationOnce((params, callback) => { - callback(null, 'data'); - }); - - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - const params = {event: { name: '_update_endpoint', immediate: true}}; - await analytics.record(params, {resolve, reject}); - expect(spyon.mock.calls[0][0]).toEqual({ - "ApplicationId": "appId", - "EndpointId": "endpointId", - "EndpointRequest": { - "Attributes": {}, - "ChannelType": undefined, - "Demographic": { - "AppVersion": "clientInfoAppVersion", - "Locale": "locale", - "Make": "make", - "Model": "model", - "ModelVersion": "clientInfoVersion", - "Platform": "platform", - "PlatformVersion": "platformVersion", - }, - "EffectiveDate": "isoString", - "Location": {}, - "Metrics": {}, - "RequestId": "uuid", - "User": { - "UserAttributes": {}, - "UserId": "identityId" - } - } - }); - - spyon.mockClear(); - }); - - test('happy case with default enpoint configure provided', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure(optionsWithDefaultEndpointConfigure); - const spyon = jest.spyOn(Pinpoint.prototype, 'updateEndpoint').mockImplementationOnce((params, callback) => { - callback(null, 'data'); - }); - - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - const params = {event: { name: '_update_endpoint', immediate: true}}; - await analytics.record(params, {resolve, reject}); - - expect(spyon.mock.calls[0][0]).toEqual({ - "ApplicationId":"appId", - "EndpointId":"endpointId", - "EndpointRequest":{ - "Address":"default", - "Attributes":{ - "hobbies":[ - "default" - ] - }, - "ChannelType":"default", - "Demographic":{ - "AppVersion":"default", - "Locale":"default", - "Make":"default", - "Model":"default", - "ModelVersion":"default", - "Platform":"default", - "PlatformVersion":"default", - "Timezone":"default" - }, - "EffectiveDate":"isoString", - "Location":{ - "City":"default", - "Country":"default", - "Latitude":0, - "Longitude":0, - "PostalCode":"default", - "Region":"default" - }, - "Metrics":{ - - }, - "OptOut":"default", - "RequestId":"uuid", - "User":{ - "UserAttributes":{ - "interests":[ - "default" - ] - }, - "UserId":"default" - } - } - }); - - spyon.mockClear(); - }); - - test('happy case with specified enpoint configure provided', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure(optionsWithDefaultEndpointConfigure); - const spyon = jest.spyOn(Pinpoint.prototype, 'updateEndpoint').mockImplementationOnce((params, callback) => { - callback(null, 'data'); - }); - - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - const {UserId, UserAttributes, ...endpointRequestContext} = endpointConfigure; - - const params = {event: { name: '_update_endpoint', immediate: true, ...endpointConfigure}}; - await analytics.record(params, {resolve, reject}); - - expect(spyon.mock.calls[0][0]).toEqual({ - "ApplicationId":"appId", - "EndpointId":"endpointId", - "EndpointRequest":{ - "Address":"configured", - "Attributes":{ - "hobbies":[ - "configured" - ] - }, - "ChannelType":"configured", - "Demographic":{ - "AppVersion":"configured", - "Locale":"configured", - "Make":"configured", - "Model":"configured", - "ModelVersion":"configured", - "Platform":"configured", - "PlatformVersion":"configured", - "Timezone":"configured" - }, - "EffectiveDate":"isoString", - "Location":{ - "City":"configured", - "Country":"configured", - "Latitude":0, - "Longitude":0, - "PostalCode":"configured", - "Region":"configured" - }, - "Metrics":{ - - }, - "OptOut":"configured", - "RequestId":"uuid", - "User":{ - "UserAttributes":{ - "interests":[ - "configured" - ] - }, - "UserId":"configured" - } - } - }); - - spyon.mockClear(); - }); - - - - test('error case', async () => { - const analytics = new AnalyticsProvider(); - analytics.configure( - options - ); - const spyon = jest.spyOn(Pinpoint.prototype, 'updateEndpoint').mockImplementationOnce((params, callback) => { - callback({ message: 'error' }, null); - }); - - jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return Promise.resolve(credentials); - }); - - - const params = {event: { name: '_update_endpoint', immediate: true}}; - - await analytics.record(params, {resolve, reject}); - expect(reject).toBeCalled(); - spyon.mockClear(); - }); - }); - }); -}); \ No newline at end of file +describe('AnalyticsProvider test', () => { + describe('getCategory test', () => { + test('happy case', () => { + const analytics = new AnalyticsProvider(); + + expect(analytics.getCategory()).toBe('Analytics'); + }); + }); + + describe('getProviderName test', () => { + test('happy case', () => { + const analytics = new AnalyticsProvider(); + + expect(analytics.getProviderName()).toBe('AWSPinpoint'); + }); + }); + + describe('configure test', () => { + test('happy case', () => { + const analytics = new AnalyticsProvider(); + + expect(analytics.configure({ appId: 'appId' })).toEqual({ + appId: 'appId', + bufferSize: 1000, + flushInterval: 5000, + flushSize: 100, + resendLimit: 5, + }); + }); + }); + + describe('record test', () => { + test('record without credentials', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(options); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return Promise.reject('err'); + }); + + await analytics.record('params', { resolve, reject }); + expect(reject).toBeCalled(); + spyon.mockClear(); + }); + + test('record without appId', async () => { + const analytics = new AnalyticsProvider(); + const { appId, ...rest } = options; + analytics.configure(rest); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + await analytics.record('params', { resolve, reject }); + expect(reject).toBeCalled(); + spyon.mockClear(); + }); + + test('record without region', async () => { + const analytics = new AnalyticsProvider(); + const { region, ...rest } = options; + analytics.configure(rest); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + await analytics.record('params', { resolve, reject }); + expect(reject).toBeCalled(); + spyon.mockClear(); + }); + + describe('record test', () => { + test('custom events', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(options); + const spyon = jest + .spyOn(Pinpoint.prototype, 'putEvents') + .mockImplementationOnce(params => { + return { + on(event, callback) { + return; + }, + send(callback) { + callback(null, response); + }, + }; + }); + + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + const params = { event: { name: 'custom event', immediate: true } }; + await analytics.record(params, { resolve, reject }); + + expect(spyon).toBeCalledWith({ + ApplicationId: 'appId', + EventsRequest: { + BatchItem: { + endpointId: { + Endpoint: {}, + Events: { + uuid: { + Attributes: undefined, + EventType: 'custom event', + Metrics: undefined, + Session: { + Id: 'uuid', + StartTimestamp: 'isoString', + }, + Timestamp: 'isoString', + }, + }, + }, + }, + }, + }); + expect(resolve).toBeCalled(); + spyon.mockClear(); + }); + + test('custom event error', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(options); + + const spyon = jest + .spyOn(Pinpoint.prototype, 'putEvents') + .mockImplementationOnce(params => { + return { + on(event, callback) { + return; + }, + send(callback) { + callback('err', null); + }, + }; + }); + + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + const params = { event: { name: 'custom event', immediate: true } }; + + await analytics.record(params, { resolve, reject }); + expect(reject).toBeCalled(); + spyon.mockClear(); + }); + }); + + describe('startsession test', () => { + test('happy case', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(options); + const spyon = jest + .spyOn(Pinpoint.prototype, 'putEvents') + .mockImplementationOnce(params => { + return { + on(event, callback) { + return; + }, + send(callback) { + callback(null, response); + }, + }; + }); + + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + const params = { event: { name: '_session.start', immediate: true } }; + await analytics.record(params, { resolve, reject }); + + expect(spyon).toBeCalledWith({ + ApplicationId: 'appId', + EventsRequest: { + BatchItem: { + endpointId: { + Endpoint: {}, + Events: { + uuid: { + Attributes: undefined, + EventType: '_session.start', + Metrics: undefined, + Session: { + Id: 'uuid', + StartTimestamp: 'isoString', + }, + Timestamp: 'isoString', + }, + }, + }, + }, + }, + }); + expect(resolve).toBeCalled(); + spyon.mockClear(); + }); + + test('session start error', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(options); + const spyon = jest + .spyOn(Pinpoint.prototype, 'putEvents') + .mockImplementationOnce(params => { + return { + on(event, callback) { + return; + }, + send(callback) { + callback('err', null); + }, + }; + }); + + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + const params = { event: { name: '_session.start', immediate: true } }; + + await analytics.record(params, { resolve, reject }); + //expect(resolve).not.toBeCalled(); + expect(reject).toBeCalled(); + spyon.mockClear(); + }); + }); + + describe('stopSession test', () => { + test('happy case', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(options); + + const spyon = jest + .spyOn(navigator, 'sendBeacon') + .mockImplementationOnce(params => { + return true; + }); + + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + const params = { event: { name: '_session.stop', immediate: true } }; + await analytics.record(params, { resolve, reject }); + + const expectedUrl = + 'https://pinpoint.region.amazonaws.com/v1/apps/appId/events?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=accessKeyId%2FisoStrin%2Fregion%2Fmobiletargeting%2Faws4_request&X-Amz-Date=isoString&X-Amz-Security-Token=sessionToken&X-Amz-SignedHeaders=host&X-Amz-Signature=c43336d302010144ca492cc6f42d5545e0ef01c00bc71d99dc7597351f027810'; + const expectedData = JSON.stringify({ + BatchItem: { + endpointId: { + Endpoint: {}, + Events: { + uuid: { + EventType: '_session.stop', + Timestamp: 'isoString', + Session: { + Id: 'uuid', + Duration: 0, + StartTimestamp: 'isoString', + StopTimestamp: 'isoString', + }, + }, + }, + }, + }, + }); + + expect(spyon).toBeCalledWith(expectedUrl, expectedData); + expect(resolve).toBeCalled(); + spyon.mockClear(); + }); + + test('session stop error', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(options); + const spyon = jest + .spyOn(Pinpoint.prototype, 'putEvents') + .mockImplementationOnce(params => { + return { + on(event, callback) { + return; + }, + send(callback) { + callback('err', null); + }, + }; + }); + + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + const params = { event: { name: '_session.stop', immediate: true } }; + + await analytics.record(params, { resolve, reject }); + expect(reject).toBeCalled(); + spyon.mockClear(); + }); + }); + + describe('updateEndpoint test', () => { + test('happy case with default client info', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(options); + const spyon = jest + .spyOn(Pinpoint.prototype, 'updateEndpoint') + .mockImplementationOnce((params, callback) => { + callback(null, 'data'); + }); + + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + const params = { event: { name: '_update_endpoint', immediate: true } }; + await analytics.record(params, { resolve, reject }); + expect(spyon.mock.calls[0][0]).toEqual({ + ApplicationId: 'appId', + EndpointId: 'endpointId', + EndpointRequest: { + Attributes: {}, + ChannelType: undefined, + Demographic: { + AppVersion: 'clientInfoAppVersion', + Make: 'clientInfoMake', + Model: 'clientInfoModel', + ModelVersion: 'clientInfoVersion', + Platform: 'clientInfoPlatform', + }, + EffectiveDate: 'isoString', + Location: {}, + Metrics: {}, + RequestId: 'uuid', + User: { + UserAttributes: {}, + UserId: 'identityId', + }, + }, + }); + expect(resolve).toBeCalled(); + spyon.mockClear(); + }); + + test('happy case with client context provided', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(optionsWithClientContext); + const spyon = jest + .spyOn(Pinpoint.prototype, 'updateEndpoint') + .mockImplementationOnce((params, callback) => { + callback(null, 'data'); + }); + + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + const params = { event: { name: '_update_endpoint', immediate: true } }; + await analytics.record(params, { resolve, reject }); + expect(spyon.mock.calls[0][0]).toEqual({ + ApplicationId: 'appId', + EndpointId: 'endpointId', + EndpointRequest: { + Attributes: {}, + ChannelType: undefined, + Demographic: { + AppVersion: 'clientInfoAppVersion', + Locale: 'locale', + Make: 'make', + Model: 'model', + ModelVersion: 'clientInfoVersion', + Platform: 'platform', + PlatformVersion: 'platformVersion', + }, + EffectiveDate: 'isoString', + Location: {}, + Metrics: {}, + RequestId: 'uuid', + User: { + UserAttributes: {}, + UserId: 'identityId', + }, + }, + }); + + spyon.mockClear(); + }); + + test('happy case with default enpoint configure provided', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(optionsWithDefaultEndpointConfigure); + const spyon = jest + .spyOn(Pinpoint.prototype, 'updateEndpoint') + .mockImplementationOnce((params, callback) => { + callback(null, 'data'); + }); + + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + const params = { event: { name: '_update_endpoint', immediate: true } }; + await analytics.record(params, { resolve, reject }); + + expect(spyon.mock.calls[0][0]).toEqual({ + ApplicationId: 'appId', + EndpointId: 'endpointId', + EndpointRequest: { + Address: 'default', + Attributes: { + hobbies: ['default'], + }, + ChannelType: 'default', + Demographic: { + AppVersion: 'default', + Locale: 'default', + Make: 'default', + Model: 'default', + ModelVersion: 'default', + Platform: 'default', + PlatformVersion: 'default', + Timezone: 'default', + }, + EffectiveDate: 'isoString', + Location: { + City: 'default', + Country: 'default', + Latitude: 0, + Longitude: 0, + PostalCode: 'default', + Region: 'default', + }, + Metrics: {}, + OptOut: 'default', + RequestId: 'uuid', + User: { + UserAttributes: { + interests: ['default'], + }, + UserId: 'default', + }, + }, + }); + + spyon.mockClear(); + }); + + test('happy case with specified enpoint configure provided', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(optionsWithDefaultEndpointConfigure); + const spyon = jest + .spyOn(Pinpoint.prototype, 'updateEndpoint') + .mockImplementationOnce((params, callback) => { + callback(null, 'data'); + }); + + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + const { + UserId, + UserAttributes, + ...endpointRequestContext + } = endpointConfigure; + + const params = { + event: { + name: '_update_endpoint', + immediate: true, + ...endpointConfigure, + }, + }; + await analytics.record(params, { resolve, reject }); + + expect(spyon.mock.calls[0][0]).toEqual({ + ApplicationId: 'appId', + EndpointId: 'endpointId', + EndpointRequest: { + Address: 'configured', + Attributes: { + hobbies: ['configured'], + }, + ChannelType: 'configured', + Demographic: { + AppVersion: 'configured', + Locale: 'configured', + Make: 'configured', + Model: 'configured', + ModelVersion: 'configured', + Platform: 'configured', + PlatformVersion: 'configured', + Timezone: 'configured', + }, + EffectiveDate: 'isoString', + Location: { + City: 'configured', + Country: 'configured', + Latitude: 0, + Longitude: 0, + PostalCode: 'configured', + Region: 'configured', + }, + Metrics: {}, + OptOut: 'configured', + RequestId: 'uuid', + User: { + UserAttributes: { + interests: ['configured'], + }, + UserId: 'configured', + }, + }, + }); + + spyon.mockClear(); + }); + + test('error case', async () => { + const analytics = new AnalyticsProvider(); + analytics.configure(options); + const spyon = jest + .spyOn(Pinpoint.prototype, 'updateEndpoint') + .mockImplementationOnce((params, callback) => { + callback({ message: 'error' }, null); + }); + + jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return Promise.resolve(credentials); + }); + + const params = { event: { name: '_update_endpoint', immediate: true } }; + + await analytics.record(params, { resolve, reject }); + expect(reject).toBeCalled(); + spyon.mockClear(); + }); + }); + }); +}); diff --git a/packages/analytics/__tests__/trackers/EventTracker-test.ts b/packages/analytics/__tests__/trackers/EventTracker-test.ts index 2f3423d8272..53037636403 100644 --- a/packages/analytics/__tests__/trackers/EventTracker-test.ts +++ b/packages/analytics/__tests__/trackers/EventTracker-test.ts @@ -1,119 +1,124 @@ const mockDelegate = jest.fn(); const tracker = jest.fn().mockImplementation(() => { - return Promise.resolve(); + return Promise.resolve(); }); jest.mock('../../src/vendor/dom-utils', () => { - return { - delegate: mockDelegate - } + return { + delegate: mockDelegate, + }; }); import EventTracker from '../../src/trackers/EventTracker'; describe('EventTracer test', () => { - describe('environment test', () => { - test('not in the web env', () => { - let eventListener = window.addEventListener; - window.addEventListener = null; - const eventTracker = new EventTracker(tracker, { - enable: true - }); - - const spyon = jest.spyOn(eventTracker, 'configure').mockImplementationOnce(() => { - return; - }); - - expect(spyon).not.toBeCalled(); - - spyon.mockClear(); - window.addEventListener = eventListener; - }); - - test('in the web env', () => { - const spyon = jest.spyOn(EventTracker.prototype, 'configure').mockImplementationOnce(() => { - return; - }); - - const eventTracker = new EventTracker(tracker, { - enable: true - }); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - - }); - - describe('configure test', () => { - test('happy case', () => { - const eventTracker = new EventTracker(tracker, { - enable: true - }); - - expect(eventTracker.configure({ - enable: true, - selectorPrefix: 'prefix', - events: ['click', 'mouseover'], - provider: 'myProvider', - attributes: { - attr: 'attr' - } - })).toEqual({ - enable: true, - selectorPrefix: 'prefix', - events: ['click', 'mouseover'], - provider: 'myProvider', - attributes: { - attr: 'attr' - } - }); - - expect(mockDelegate).toBeCalled(); - - mockDelegate.mockClear(); - }); - }); - - describe('track function test', () => { - test('happy case', () => { - const ele = { - getAttribute(params) { - if (params.indexOf('on') >= 0) return 'click'; - if (params.indexOf('name') >= 0) return 'name'; - if (params.indexOf('attrs') >= 0) return 'attrs:val'; - } - } - - const eventTracker = new EventTracker(tracker, { - enable: true, - attributes: { - browser: 'chrome' - } - }); - - const event = { - type: 'click', - target: { - localName: 'localName', - id: 'xxxxx' - } - } - eventTracker._trackFunc(event, ele); - - expect(tracker).toBeCalledWith( - { - "attributes": { - "attrs": "val", - "target": "localName with id xxxxx", - "type": "click", - "browser" : "chrome" - }, - "name": "name" - }, - 'AWSPinpoint' - ); - }); - }); -}); \ No newline at end of file + describe('environment test', () => { + test('not in the web env', () => { + let eventListener = window.addEventListener; + window.addEventListener = null; + const eventTracker = new EventTracker(tracker, { + enable: true, + }); + + const spyon = jest + .spyOn(eventTracker, 'configure') + .mockImplementationOnce(() => { + return; + }); + + expect(spyon).not.toBeCalled(); + + spyon.mockClear(); + window.addEventListener = eventListener; + }); + + test('in the web env', () => { + const spyon = jest + .spyOn(EventTracker.prototype, 'configure') + .mockImplementationOnce(() => { + return; + }); + + const eventTracker = new EventTracker(tracker, { + enable: true, + }); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + }); + + describe('configure test', () => { + test('happy case', () => { + const eventTracker = new EventTracker(tracker, { + enable: true, + }); + + expect( + eventTracker.configure({ + enable: true, + selectorPrefix: 'prefix', + events: ['click', 'mouseover'], + provider: 'myProvider', + attributes: { + attr: 'attr', + }, + }) + ).toEqual({ + enable: true, + selectorPrefix: 'prefix', + events: ['click', 'mouseover'], + provider: 'myProvider', + attributes: { + attr: 'attr', + }, + }); + + expect(mockDelegate).toBeCalled(); + + mockDelegate.mockClear(); + }); + }); + + describe('track function test', () => { + test('happy case', () => { + const ele = { + getAttribute(params) { + if (params.indexOf('on') >= 0) return 'click'; + if (params.indexOf('name') >= 0) return 'name'; + if (params.indexOf('attrs') >= 0) return 'attrs:val'; + }, + }; + + const eventTracker = new EventTracker(tracker, { + enable: true, + attributes: { + browser: 'chrome', + }, + }); + + const event = { + type: 'click', + target: { + localName: 'localName', + id: 'xxxxx', + }, + }; + eventTracker._trackFunc(event, ele); + + expect(tracker).toBeCalledWith( + { + attributes: { + attrs: 'val', + target: 'localName with id xxxxx', + type: 'click', + browser: 'chrome', + }, + name: 'name', + }, + 'AWSPinpoint' + ); + }); + }); +}); diff --git a/packages/analytics/__tests__/trackers/PageViewTracker-test.ts b/packages/analytics/__tests__/trackers/PageViewTracker-test.ts index 3ee1b771071..356b6ec9905 100644 --- a/packages/analytics/__tests__/trackers/PageViewTracker-test.ts +++ b/packages/analytics/__tests__/trackers/PageViewTracker-test.ts @@ -2,216 +2,224 @@ import PageViewTracker from '../../src/trackers/PageViewTracker'; import MethodEmbed from '../../src/utils/MethodEmbed'; const tracker = jest.fn().mockImplementation(() => { - return Promise.resolve(); + return Promise.resolve(); }); class SessionStorageMock { - private store; - private maxSize; - private curSize; - private length; - - constructor() { - this.store = {}; - this.maxSize = 5000; - this.curSize = 0; - this.length = 0; - } - - getByteLength(str) { - var ret = str.length - - for (var i = str.length; i >= 0; i--) { - var charCode = str.charCodeAt(i); - if (charCode > 0x7f && charCode <= 0x7ff) { - ++ret; - } - else if (charCode > 0x7ff && charCode <= 0xffff) { - ret += 2; - } - if (charCode >= 0xDC00 && charCode <= 0xDFFF) { - i--; //trail surrogate - } - } - return ret; - } - - clear() { - this.store = {}; - this.curSize = 0; - } - - getItem(key) { - return this.store[key] || null; - } - - setItem(key, value) { - if (key in this.store) { - this.removeItem(key); - } - if (this.curSize + this.getByteLength(value.toString()) > this.maxSize) { - throw new Error('session storage is full!'); - } - else { - this.store[key] = value.toString(); - this.curSize += this.getByteLength(this.store[key]); - ++this.length; - //console.log('current size in session storage: ' + this.curSize); - } - } - - removeItem(key) { - this.curSize -= this.getByteLength(this.store[key]); - delete this.store[key]; - --this.length; - } - - showItems() { - var str = ''; - for (var key in this.store){ - str += key + '\n'; - } - str = 'show items in mock cache: \n' + str; - console.log(str); - } - - setSize(size) { - this.maxSize = size; - } - - getSize() { - return this.maxSize; - } - - key(i) { - var keys = Object.keys(this.store); - return keys[i]; - } -}; - -window.sessionStorage = new SessionStorageMock; + private store; + private maxSize; + private curSize; + private length; + + constructor() { + this.store = {}; + this.maxSize = 5000; + this.curSize = 0; + this.length = 0; + } + + getByteLength(str) { + var ret = str.length; + + for (var i = str.length; i >= 0; i--) { + var charCode = str.charCodeAt(i); + if (charCode > 0x7f && charCode <= 0x7ff) { + ++ret; + } else if (charCode > 0x7ff && charCode <= 0xffff) { + ret += 2; + } + if (charCode >= 0xdc00 && charCode <= 0xdfff) { + i--; //trail surrogate + } + } + return ret; + } + + clear() { + this.store = {}; + this.curSize = 0; + } + + getItem(key) { + return this.store[key] || null; + } + + setItem(key, value) { + if (key in this.store) { + this.removeItem(key); + } + if (this.curSize + this.getByteLength(value.toString()) > this.maxSize) { + throw new Error('session storage is full!'); + } else { + this.store[key] = value.toString(); + this.curSize += this.getByteLength(this.store[key]); + ++this.length; + //console.log('current size in session storage: ' + this.curSize); + } + } + + removeItem(key) { + this.curSize -= this.getByteLength(this.store[key]); + delete this.store[key]; + --this.length; + } + + showItems() { + var str = ''; + for (var key in this.store) { + str += key + '\n'; + } + str = 'show items in mock cache: \n' + str; + console.log(str); + } + + setSize(size) { + this.maxSize = size; + } + + getSize() { + return this.maxSize; + } + + key(i) { + var keys = Object.keys(this.store); + return keys[i]; + } +} + +window.sessionStorage = new SessionStorageMock(); describe('PageViewTracker test', () => { - describe('constructor test', () => { - test('happy case with type SPA', () => { - const spyon = jest.spyOn(MethodEmbed, 'add').mockImplementation(() => { - return; - }); - const spyon2 = jest.spyOn(window, 'addEventListener').mockImplementation(() => { - return; - }); - const pageViewTracer = new PageViewTracker(tracker, { - enable: true, - type: 'SPA' - }); - - expect(spyon).toBeCalled(); - expect(spyon2).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('type SPA, in unsupported env', () => { - let tmp = window.addEventListener; - window.addEventListener = undefined; - - const spyon = jest.spyOn(MethodEmbed, 'add').mockImplementation(() => { - return; - }); - - const pageViewTracer = new PageViewTracker(tracker, { - enable: true, - type: 'SPA' - }); - - expect(spyon).not.toBeCalled(); - - spyon.mockClear(); - - window.addEventListener = tmp; - }); - - test.skip('happy case with type default', () => { - tracker.mockClear(); - - const spyon = jest.spyOn(sessionStorage, 'getItem').mockImplementation(() => { - return 'url1'; - }); - - const spyon2 = jest.spyOn(sessionStorage, 'setItem').mockImplementation(() => { - return; - }); - - const pageViewTracer = new PageViewTracker(tracker, { - enable: true - }); - - expect(tracker).toBeCalled(); - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('type default, in unsupported env', () => { - tracker.mockClear(); - - let tmp = window.addEventListener; - window.addEventListener = undefined; - - const pageViewTracer = new PageViewTracker(tracker, { - enable: true - }); - - expect(tracker).not.toBeCalled(); - window.addEventListener = tmp; - }); - }); - - describe('configure test', () => { - test('happy case', () => { - const pageViewTracer = new PageViewTracker(tracker, { - enable: true - }); - - const getUrlMock = jest.fn(); - expect(pageViewTracer.configure({ - enable: true, - attributes: { - attr: 'attr' - }, - provider: 'myProvider', - getUrl: getUrlMock - })).toEqual({ - enable: true, - attributes: { - attr: 'attr' - }, - provider: 'myProvider', - getUrl: getUrlMock - }); - }); - - test('turn off autoTrack', () => { - const spyon = jest.spyOn(MethodEmbed, 'remove').mockImplementation(() => { - return; - }); - const spyon2 = jest.spyOn(window, 'removeEventListener').mockImplementation(() => { - return; - }); - const pageViewTracer = new PageViewTracker(tracker, { - enable: true, - type: 'SPA' - }); - - pageViewTracer.configure({ - enable: false - }); - - expect(spyon).toBeCalled(); - expect(spyon2).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); -}); \ No newline at end of file + describe('constructor test', () => { + test('happy case with type SPA', () => { + const spyon = jest.spyOn(MethodEmbed, 'add').mockImplementation(() => { + return; + }); + const spyon2 = jest + .spyOn(window, 'addEventListener') + .mockImplementation(() => { + return; + }); + const pageViewTracer = new PageViewTracker(tracker, { + enable: true, + type: 'SPA', + }); + + expect(spyon).toBeCalled(); + expect(spyon2).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('type SPA, in unsupported env', () => { + let tmp = window.addEventListener; + window.addEventListener = undefined; + + const spyon = jest.spyOn(MethodEmbed, 'add').mockImplementation(() => { + return; + }); + + const pageViewTracer = new PageViewTracker(tracker, { + enable: true, + type: 'SPA', + }); + + expect(spyon).not.toBeCalled(); + + spyon.mockClear(); + + window.addEventListener = tmp; + }); + + test.skip('happy case with type default', () => { + tracker.mockClear(); + + const spyon = jest + .spyOn(sessionStorage, 'getItem') + .mockImplementation(() => { + return 'url1'; + }); + + const spyon2 = jest + .spyOn(sessionStorage, 'setItem') + .mockImplementation(() => { + return; + }); + + const pageViewTracer = new PageViewTracker(tracker, { + enable: true, + }); + + expect(tracker).toBeCalled(); + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('type default, in unsupported env', () => { + tracker.mockClear(); + + let tmp = window.addEventListener; + window.addEventListener = undefined; + + const pageViewTracer = new PageViewTracker(tracker, { + enable: true, + }); + + expect(tracker).not.toBeCalled(); + window.addEventListener = tmp; + }); + }); + + describe('configure test', () => { + test('happy case', () => { + const pageViewTracer = new PageViewTracker(tracker, { + enable: true, + }); + + const getUrlMock = jest.fn(); + expect( + pageViewTracer.configure({ + enable: true, + attributes: { + attr: 'attr', + }, + provider: 'myProvider', + getUrl: getUrlMock, + }) + ).toEqual({ + enable: true, + attributes: { + attr: 'attr', + }, + provider: 'myProvider', + getUrl: getUrlMock, + }); + }); + + test('turn off autoTrack', () => { + const spyon = jest.spyOn(MethodEmbed, 'remove').mockImplementation(() => { + return; + }); + const spyon2 = jest + .spyOn(window, 'removeEventListener') + .mockImplementation(() => { + return; + }); + const pageViewTracer = new PageViewTracker(tracker, { + enable: true, + type: 'SPA', + }); + + pageViewTracer.configure({ + enable: false, + }); + + expect(spyon).toBeCalled(); + expect(spyon2).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); +}); diff --git a/packages/analytics/__tests__/trackers/SessionTracker-rn-test.ts b/packages/analytics/__tests__/trackers/SessionTracker-rn-test.ts index c113025db19..494beb01c2b 100644 --- a/packages/analytics/__tests__/trackers/SessionTracker-rn-test.ts +++ b/packages/analytics/__tests__/trackers/SessionTracker-rn-test.ts @@ -2,104 +2,115 @@ const mockAddEventListener = jest.fn(); const mockRemoveEventListener = jest.fn(); jest.mock('react-native', () => { - return { - AppState: { - currentState: 'inactive', - addEventListener: mockAddEventListener, - removeEventListener: mockRemoveEventListener - } - } + return { + AppState: { + currentState: 'inactive', + addEventListener: mockAddEventListener, + removeEventListener: mockRemoveEventListener, + }, + }; }); import SessionTracker from '../../src/trackers/SessionTracker-rn'; import { AppState } from 'react-native'; const tracker = jest.fn().mockImplementation(() => { - return Promise.resolve(); + return Promise.resolve(); }); describe('SessionTracker test', () => { - describe('constructor test', () => { - test('happy case', () => { - tracker.mockClear(); - - const sessionTracker = new SessionTracker(tracker, { - enable: true - }); - - expect(tracker).toBeCalledWith({ - name: '_session.start', - attributes: {} - }, 'AWSPinpoint'); - expect(mockAddEventListener).toBeCalled(); - - mockAddEventListener.mockClear(); - }); - }); - - describe('configure test', () => { - test('happy case', () => { - const sessionTracker = new SessionTracker(tracker, { - enable: true - }); - - expect(sessionTracker.configure({ - enable: true, - attributes: { - attr1: 'val1' - }, - provider: 'myProvider' - })).toEqual({ - enable: true, - attributes: { - attr1: 'val1' - }, - provider: 'myProvider' - }); - }); - - test('autoTrack disabled', () => { - const sessionTracker = new SessionTracker(tracker, { - enable: true - }); - - mockRemoveEventListener.mockClear(); - - sessionTracker.configure({ - enable: false - }); - - expect(mockRemoveEventListener).toBeCalled(); - mockRemoveEventListener.mockClear(); - }); - }); - - describe('track function test', () => { - test('if the app turns to be active', () => { - const sessionTracker = new SessionTracker(tracker, { - enable: true - }); - tracker.mockClear(); - - // mock to be inactive - sessionTracker._currentState = 'inactive'; - sessionTracker._trackFunc('active'); - - expect(tracker).toBeCalledWith({ - name: '_session.start', - attributes: {} - }, 'AWSPinpoint'); - }); - - test('if app turns into background', () => { - const sessionTracker = new SessionTracker(tracker, { - enable: true - }); - tracker.mockClear(); - - sessionTracker._trackFunc('inactive'); - - expect(tracker).toBeCalledWith({"attributes": {}, "immediate": true, "name": "_session.stop"}, 'AWSPinpoint'); - }); - }); -}); \ No newline at end of file + describe('constructor test', () => { + test('happy case', () => { + tracker.mockClear(); + + const sessionTracker = new SessionTracker(tracker, { + enable: true, + }); + + expect(tracker).toBeCalledWith( + { + name: '_session.start', + attributes: {}, + }, + 'AWSPinpoint' + ); + expect(mockAddEventListener).toBeCalled(); + + mockAddEventListener.mockClear(); + }); + }); + + describe('configure test', () => { + test('happy case', () => { + const sessionTracker = new SessionTracker(tracker, { + enable: true, + }); + + expect( + sessionTracker.configure({ + enable: true, + attributes: { + attr1: 'val1', + }, + provider: 'myProvider', + }) + ).toEqual({ + enable: true, + attributes: { + attr1: 'val1', + }, + provider: 'myProvider', + }); + }); + + test('autoTrack disabled', () => { + const sessionTracker = new SessionTracker(tracker, { + enable: true, + }); + + mockRemoveEventListener.mockClear(); + + sessionTracker.configure({ + enable: false, + }); + + expect(mockRemoveEventListener).toBeCalled(); + mockRemoveEventListener.mockClear(); + }); + }); + + describe('track function test', () => { + test('if the app turns to be active', () => { + const sessionTracker = new SessionTracker(tracker, { + enable: true, + }); + tracker.mockClear(); + + // mock to be inactive + sessionTracker._currentState = 'inactive'; + sessionTracker._trackFunc('active'); + + expect(tracker).toBeCalledWith( + { + name: '_session.start', + attributes: {}, + }, + 'AWSPinpoint' + ); + }); + + test('if app turns into background', () => { + const sessionTracker = new SessionTracker(tracker, { + enable: true, + }); + tracker.mockClear(); + + sessionTracker._trackFunc('inactive'); + + expect(tracker).toBeCalledWith( + { attributes: {}, immediate: true, name: '_session.stop' }, + 'AWSPinpoint' + ); + }); + }); +}); diff --git a/packages/analytics/__tests__/trackers/SessionTracker-test.ts b/packages/analytics/__tests__/trackers/SessionTracker-test.ts index 4798148b668..e9fad9e58b6 100644 --- a/packages/analytics/__tests__/trackers/SessionTracker-test.ts +++ b/packages/analytics/__tests__/trackers/SessionTracker-test.ts @@ -1,138 +1,151 @@ import SessionTracker from '../../src/trackers/SessionTracker'; const tracker = jest.fn().mockImplementation(() => { - return Promise.resolve(); + return Promise.resolve(); }); - - describe('SessionTracker test', () => { - describe('constructor test', () => { - test('happy case', () => { - tracker.mockClear(); - - const spyon = jest.spyOn(document, 'addEventListener').mockImplementationOnce(() => { - return; - }); - - const sessionTracker = new SessionTracker(tracker, { - enable: true - }); - - expect(tracker).toBeCalledWith({ - name: '_session.start', - attributes: {} - }, 'AWSPinpoint'); - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - - test('not in the supported env', () => { - tracker.mockClear(); - let tmp = document; - Object.defineProperty(window.document, 'hidden', { - writable: true, - value: undefined - }); - - const sessionTracker = new SessionTracker(tracker, { - enable: true - }); - - expect(tracker).not.toBeCalled(); - Object.defineProperty(window.document, 'hidden', { - writable: true, - value: false - }); - }); - }); - - describe('configure test', () => { - test('happy case', () => { - const sessionTracker = new SessionTracker(tracker, { - enable: true - }); - - expect(sessionTracker.configure({ - enable: true, - attributes: { - attr1: 'val1' - }, - provider: 'myProvider' - })).toEqual({ - enable: true, - attributes: { - attr1: 'val1' - }, - provider: 'myProvider' - }); - }); - - test('autoTrack disabled', () => { - const sessionTracker = new SessionTracker(tracker, { - enable: true - }); - - const spyon = jest.spyOn(document, 'removeEventListener').mockImplementationOnce(() => { - return; - }); - sessionTracker.configure({ - enable: false - }); - - expect(spyon).toBeCalled(); - spyon.mockClear(); - }); - }); - - describe('track function test', () => { - test('if the page is hidden', async () => { - const sessionTracker = new SessionTracker(tracker, { - enable: true - }); - tracker.mockClear(); - - Object.defineProperty(window.document, 'hidden', { - writable: true, - value: true - }); - - Object.defineProperty(window.document, 'visibilityState', { - writable: true, - value: 'hidden' - }); - - await sessionTracker._trackFunc(); - - expect(tracker).toBeCalledWith({ - name: '_session.stop', - attributes: {} - }, 'AWSPinpoint'); - }); - - test('if the page is not hidden', async () => { - const sessionTracker = new SessionTracker(tracker, { - enable: true - }); - tracker.mockClear(); - - Object.defineProperty(window.document, 'hidden', { - writable: true, - value: false - }); - - Object.defineProperty(window.document, 'visibilityState', { - writable: true, - value: 'visible' - }); - - await sessionTracker._trackFunc(); - - expect(tracker).toBeCalledWith({ - name: '_session.start', - attributes: {} - }, 'AWSPinpoint'); - }); - }); -}); \ No newline at end of file + describe('constructor test', () => { + test('happy case', () => { + tracker.mockClear(); + + const spyon = jest + .spyOn(document, 'addEventListener') + .mockImplementationOnce(() => { + return; + }); + + const sessionTracker = new SessionTracker(tracker, { + enable: true, + }); + + expect(tracker).toBeCalledWith( + { + name: '_session.start', + attributes: {}, + }, + 'AWSPinpoint' + ); + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + + test('not in the supported env', () => { + tracker.mockClear(); + let tmp = document; + Object.defineProperty(window.document, 'hidden', { + writable: true, + value: undefined, + }); + + const sessionTracker = new SessionTracker(tracker, { + enable: true, + }); + + expect(tracker).not.toBeCalled(); + Object.defineProperty(window.document, 'hidden', { + writable: true, + value: false, + }); + }); + }); + + describe('configure test', () => { + test('happy case', () => { + const sessionTracker = new SessionTracker(tracker, { + enable: true, + }); + + expect( + sessionTracker.configure({ + enable: true, + attributes: { + attr1: 'val1', + }, + provider: 'myProvider', + }) + ).toEqual({ + enable: true, + attributes: { + attr1: 'val1', + }, + provider: 'myProvider', + }); + }); + + test('autoTrack disabled', () => { + const sessionTracker = new SessionTracker(tracker, { + enable: true, + }); + + const spyon = jest + .spyOn(document, 'removeEventListener') + .mockImplementationOnce(() => { + return; + }); + sessionTracker.configure({ + enable: false, + }); + + expect(spyon).toBeCalled(); + spyon.mockClear(); + }); + }); + + describe('track function test', () => { + test('if the page is hidden', async () => { + const sessionTracker = new SessionTracker(tracker, { + enable: true, + }); + tracker.mockClear(); + + Object.defineProperty(window.document, 'hidden', { + writable: true, + value: true, + }); + + Object.defineProperty(window.document, 'visibilityState', { + writable: true, + value: 'hidden', + }); + + await sessionTracker._trackFunc(); + + expect(tracker).toBeCalledWith( + { + name: '_session.stop', + attributes: {}, + }, + 'AWSPinpoint' + ); + }); + + test('if the page is not hidden', async () => { + const sessionTracker = new SessionTracker(tracker, { + enable: true, + }); + tracker.mockClear(); + + Object.defineProperty(window.document, 'hidden', { + writable: true, + value: false, + }); + + Object.defineProperty(window.document, 'visibilityState', { + writable: true, + value: 'visible', + }); + + await sessionTracker._trackFunc(); + + expect(tracker).toBeCalledWith( + { + name: '_session.start', + attributes: {}, + }, + 'AWSPinpoint' + ); + }); + }); +}); diff --git a/packages/analytics/src/Analytics.ts b/packages/analytics/src/Analytics.ts index aa8f43e65c0..77ddc7de52f 100644 --- a/packages/analytics/src/Analytics.ts +++ b/packages/analytics/src/Analytics.ts @@ -12,267 +12,299 @@ */ import { - ConsoleLogger as Logger, - missingConfig, - Hub, - Parser, - Platform + ConsoleLogger as Logger, + missingConfig, + Hub, + Parser, + Platform, } from '@aws-amplify/core'; import AWSPinpointProvider from './Providers/AWSPinpointProvider'; -import { AnalyticsProvider, EventAttributes, EventMetrics, pageViewTrackOpts } from './types'; +import { + AnalyticsProvider, + EventAttributes, + EventMetrics, + pageViewTrackOpts, +} from './types'; import { PageViewTracker, EventTracker, SessionTracker } from './trackers'; const logger = new Logger('AnalyticsClass'); -const AMPLIFY_SYMBOL = ((typeof Symbol !== 'undefined' && typeof Symbol.for === 'function') ? - Symbol.for('amplify_default') : '@@amplify_default') as Symbol; - -const dispatchAnalyticsEvent = (event:string, data:any, message:string) => { - Hub.dispatch('analytics', { event, data, message }, 'Analytics', AMPLIFY_SYMBOL); +const AMPLIFY_SYMBOL = (typeof Symbol !== 'undefined' && +typeof Symbol.for === 'function' + ? Symbol.for('amplify_default') + : '@@amplify_default') as Symbol; + +const dispatchAnalyticsEvent = (event: string, data: any, message: string) => { + Hub.dispatch( + 'analytics', + { event, data, message }, + 'Analytics', + AMPLIFY_SYMBOL + ); }; const trackers = { - 'pageView': PageViewTracker, - 'event': EventTracker, - 'session': SessionTracker + pageView: PageViewTracker, + event: EventTracker, + session: SessionTracker, }; /** -* Provide mobile analytics client functions -*/ + * Provide mobile analytics client functions + */ export default class AnalyticsClass { - private _config; - private _provider; - private _pluggables: AnalyticsProvider[]; - private _disabled; - private _autoSessionRecord; - private _trackers; - - /** - * Initialize Analtyics - * @param config - Configuration of the Analytics - */ - constructor() { - this._config = {}; - this._pluggables = []; - this._disabled = false; - this._trackers = {}; - - this.record = this.record.bind(this); - } - - public getModuleName() { - return 'Analytics'; - } - /** - * configure Analytics - * @param {Object} config - Configuration of the Analytics - */ - public configure(config?) { - if (!config) return this._config; - logger.debug('configure Analytics', config); - const amplifyConfig = Parser.parseMobilehubConfig(config); - this._config = Object.assign({}, this._config, amplifyConfig.Analytics, config); - - if (this._config['disabled']) { - this._disabled = true; - } - - this._pluggables.forEach((pluggable) => { - // for backward compatibility - const providerConfig = pluggable.getProviderName() === 'AWSPinpoint' && !this._config['AWSPinpoint'] ? - this._config : this._config[pluggable.getProviderName()]; - - pluggable.configure({ disabled: this._config['disabled'], ...providerConfig} ); - }); - - if (this._pluggables.length === 0) { - this.addPluggable(new AWSPinpointProvider()); - } - - // turn on the autoSessionRecord if not specified - if (this._config['autoSessionRecord'] === undefined) { - this._config['autoSessionRecord'] = true; - } - - dispatchAnalyticsEvent( - 'configured', - null, - `The Analytics category has been configured successfully` - ); - logger.debug('current configuration', this._config); - - - return this._config; - } - - /** - * add plugin into Analytics category - * @param {Object} pluggable - an instance of the plugin - */ - public addPluggable(pluggable: AnalyticsProvider) { - if (pluggable && pluggable.getCategory() === 'Analytics') { - this._pluggables.push(pluggable); - // for backward compatibility - const providerConfig = pluggable.getProviderName() === 'AWSPinpoint' && !this._config['AWSPinpoint'] ? - this._config : this._config[pluggable.getProviderName()]; - const config = { disabled: this._config['disabled'], ...providerConfig }; - pluggable.configure(config); - return config; - } - } - - /** - * Get the plugin object - * @param providerName - the name of the plugin - */ - public getPluggable(providerName) { - for (let i = 0; i < this._pluggables.length; i += 1) { - const pluggable = this._pluggables[i]; - if (pluggable.getProviderName() === providerName) { - return pluggable; - } - } - - logger.debug('No plugin found with providerName', providerName); - return null; - } - - /** - * Remove the plugin object - * @param providerName - the name of the plugin - */ - public removePluggable(providerName) { - let idx = 0; - while (idx < this._pluggables.length) { - if (this._pluggables[idx].getProviderName() === providerName) { - break; - } - idx += 1; - } - - if (idx === this._pluggables.length) { - logger.debug('No plugin found with providerName', providerName); - return; - } else { - this._pluggables.splice(idx, idx + 1); - return; - } - } - - /** - * stop sending events - */ - public disable() { - this._disabled = true; - } - - /** - * start sending events - */ - public enable() { - this._disabled = false; - } - - /** - * Record Session start - * @return - A promise which resolves if buffer doesn't overflow - */ - public async startSession(provider?: string) { - const params = { event: { name: '_session.start' }, provider }; - return this._sendEvent(params); - } - - /** - * Record Session stop - * @return - A promise which resolves if buffer doesn't overflow - */ - public async stopSession(provider?: string) { - const params = { event: { name: '_session.stop' }, provider }; - return this._sendEvent(params); - } - - /** - * Record one analytic event and send it to Pinpoint - * @param {String} name - The name of the event - * @param {Object} [attributs] - Attributes of the event - * @param {Object} [metrics] - Event metrics - * @return - A promise which resolves if buffer doesn't overflow - */ - public async record(event: string | object, provider? , metrics?: EventMetrics) { - if (!this.isAnalyticsConfigured()) { - const errMsg = 'Analytics has not been configured'; - logger.debug(errMsg); - return Promise.reject(new Error(errMsg)); - } - - let params = null; - // this is just for compatibility, going to be deprecated - if (typeof event === 'string') { - params = { - 'event': { - name: event, - attributes: provider, - metrics - }, - provider: 'AWSPinpoint' - }; - } else { - params = { event, provider }; - } - return this._sendEvent(params); - } - - public async updateEndpoint(attrs, provider?) { - const event = Object.assign({ name: '_update_endpoint' }, attrs); - - return this.record(event, provider); - } - - private _sendEvent(params) { - if (!this.isAnalyticsConfigured()) { - const errMsg = 'Analytics has not been configured'; - logger.debug(errMsg); - return Promise.reject(new Error(errMsg)); - } - - if (this._disabled) { - logger.debug('Analytics has been disabled'); - return Promise.resolve(); - } - - const provider = params.provider? params.provider: 'AWSPinpoint'; - - return new Promise((resolve, reject) => { - this._pluggables.forEach((pluggable) => { - if (pluggable.getProviderName() === provider) { - pluggable.record(params, { resolve, reject }); - } - }); - }); - } - - public autoTrack(trackerType, opts) { - if (!trackers[trackerType]) { - logger.debug('invalid tracker type'); - return; - } - - // to sync up two different configuration ways of auto session tracking - if (trackerType === 'session') { - this._config['autoSessionRecord'] = opts['enable']; - } - - const tracker = this._trackers[trackerType]; - if (!tracker) { - this._trackers[trackerType] = new (trackers[trackerType])(this.record, opts); - } else { - tracker.configure(opts); - } - } - - private isAnalyticsConfigured() { - return this._config && Object.entries(this._config).length > 0; - } + private _config; + private _provider; + private _pluggables: AnalyticsProvider[]; + private _disabled; + private _autoSessionRecord; + private _trackers; + + /** + * Initialize Analtyics + * @param config - Configuration of the Analytics + */ + constructor() { + this._config = {}; + this._pluggables = []; + this._disabled = false; + this._trackers = {}; + + this.record = this.record.bind(this); + } + + public getModuleName() { + return 'Analytics'; + } + /** + * configure Analytics + * @param {Object} config - Configuration of the Analytics + */ + public configure(config?) { + if (!config) return this._config; + logger.debug('configure Analytics', config); + const amplifyConfig = Parser.parseMobilehubConfig(config); + this._config = Object.assign( + {}, + this._config, + amplifyConfig.Analytics, + config + ); + + if (this._config['disabled']) { + this._disabled = true; + } + + this._pluggables.forEach(pluggable => { + // for backward compatibility + const providerConfig = + pluggable.getProviderName() === 'AWSPinpoint' && + !this._config['AWSPinpoint'] + ? this._config + : this._config[pluggable.getProviderName()]; + + pluggable.configure({ + disabled: this._config['disabled'], + ...providerConfig, + }); + }); + + if (this._pluggables.length === 0) { + this.addPluggable(new AWSPinpointProvider()); + } + + // turn on the autoSessionRecord if not specified + if (this._config['autoSessionRecord'] === undefined) { + this._config['autoSessionRecord'] = true; + } + + dispatchAnalyticsEvent( + 'configured', + null, + `The Analytics category has been configured successfully` + ); + logger.debug('current configuration', this._config); + + return this._config; + } + + /** + * add plugin into Analytics category + * @param {Object} pluggable - an instance of the plugin + */ + public addPluggable(pluggable: AnalyticsProvider) { + if (pluggable && pluggable.getCategory() === 'Analytics') { + this._pluggables.push(pluggable); + // for backward compatibility + const providerConfig = + pluggable.getProviderName() === 'AWSPinpoint' && + !this._config['AWSPinpoint'] + ? this._config + : this._config[pluggable.getProviderName()]; + const config = { disabled: this._config['disabled'], ...providerConfig }; + pluggable.configure(config); + return config; + } + } + + /** + * Get the plugin object + * @param providerName - the name of the plugin + */ + public getPluggable(providerName) { + for (let i = 0; i < this._pluggables.length; i += 1) { + const pluggable = this._pluggables[i]; + if (pluggable.getProviderName() === providerName) { + return pluggable; + } + } + + logger.debug('No plugin found with providerName', providerName); + return null; + } + + /** + * Remove the plugin object + * @param providerName - the name of the plugin + */ + public removePluggable(providerName) { + let idx = 0; + while (idx < this._pluggables.length) { + if (this._pluggables[idx].getProviderName() === providerName) { + break; + } + idx += 1; + } + + if (idx === this._pluggables.length) { + logger.debug('No plugin found with providerName', providerName); + return; + } else { + this._pluggables.splice(idx, idx + 1); + return; + } + } + + /** + * stop sending events + */ + public disable() { + this._disabled = true; + } + + /** + * start sending events + */ + public enable() { + this._disabled = false; + } + + /** + * Record Session start + * @return - A promise which resolves if buffer doesn't overflow + */ + public async startSession(provider?: string) { + const params = { event: { name: '_session.start' }, provider }; + return this._sendEvent(params); + } + + /** + * Record Session stop + * @return - A promise which resolves if buffer doesn't overflow + */ + public async stopSession(provider?: string) { + const params = { event: { name: '_session.stop' }, provider }; + return this._sendEvent(params); + } + + /** + * Record one analytic event and send it to Pinpoint + * @param {String} name - The name of the event + * @param {Object} [attributs] - Attributes of the event + * @param {Object} [metrics] - Event metrics + * @return - A promise which resolves if buffer doesn't overflow + */ + public async record( + event: string | object, + provider?, + metrics?: EventMetrics + ) { + if (!this.isAnalyticsConfigured()) { + const errMsg = 'Analytics has not been configured'; + logger.debug(errMsg); + return Promise.reject(new Error(errMsg)); + } + + let params = null; + // this is just for compatibility, going to be deprecated + if (typeof event === 'string') { + params = { + event: { + name: event, + attributes: provider, + metrics, + }, + provider: 'AWSPinpoint', + }; + } else { + params = { event, provider }; + } + return this._sendEvent(params); + } + + public async updateEndpoint(attrs, provider?) { + const event = Object.assign({ name: '_update_endpoint' }, attrs); + + return this.record(event, provider); + } + + private _sendEvent(params) { + if (!this.isAnalyticsConfigured()) { + const errMsg = 'Analytics has not been configured'; + logger.debug(errMsg); + return Promise.reject(new Error(errMsg)); + } + + if (this._disabled) { + logger.debug('Analytics has been disabled'); + return Promise.resolve(); + } + + const provider = params.provider ? params.provider : 'AWSPinpoint'; + + return new Promise((resolve, reject) => { + this._pluggables.forEach(pluggable => { + if (pluggable.getProviderName() === provider) { + pluggable.record(params, { resolve, reject }); + } + }); + }); + } + + public autoTrack(trackerType, opts) { + if (!trackers[trackerType]) { + logger.debug('invalid tracker type'); + return; + } + + // to sync up two different configuration ways of auto session tracking + if (trackerType === 'session') { + this._config['autoSessionRecord'] = opts['enable']; + } + + const tracker = this._trackers[trackerType]; + if (!tracker) { + this._trackers[trackerType] = new trackers[trackerType]( + this.record, + opts + ); + } else { + tracker.configure(opts); + } + } + + private isAnalyticsConfigured() { + return this._config && Object.entries(this._config).length > 0; + } } diff --git a/packages/analytics/src/Providers/AWSKinesisProvider.ts b/packages/analytics/src/Providers/AWSKinesisProvider.ts index 13cf0799bd5..12e9ccec0e1 100644 --- a/packages/analytics/src/Providers/AWSKinesisProvider.ts +++ b/packages/analytics/src/Providers/AWSKinesisProvider.ts @@ -11,7 +11,7 @@ * and limitations under the License. */ -import { ConsoleLogger as Logger, Credentials} from '@aws-amplify/core'; +import { ConsoleLogger as Logger, Credentials } from '@aws-amplify/core'; import * as Kinesis from 'aws-sdk/clients/kinesis'; import Cache from '@aws-amplify/cache'; import { AnalyticsProvider } from '../types'; @@ -21,221 +21,227 @@ const logger = new Logger('AWSKineisProvider'); // events buffer const BUFFER_SIZE = 1000; const FLUSH_SIZE = 100; -const FLUSH_INTERVAL = 5*1000; // 5s +const FLUSH_INTERVAL = 5 * 1000; // 5s const RESEND_LIMIT = 5; export default class AWSKinesisProvider implements AnalyticsProvider { - - private _config; - private _kinesis; - private _buffer; - private _timer; - - constructor(config?) { - this._buffer = []; - this._config = config? config : {}; - this._config.bufferSize = this._config.bufferSize || BUFFER_SIZE; - this._config.flushSize = this._config.flushSize || FLUSH_SIZE; - this._config.flushInterval = this._config.flushInterval || FLUSH_INTERVAL; - this._config.resendLimit = this._config.resendLimit || RESEND_LIMIT; - - // events batch - const that = this; - - // flush event buffer - this._setupTimer(); - } - - private _setupTimer() { - if (this._timer) { - clearInterval(this._timer); - } - const { flushSize, flushInterval } = this._config; - const that = this; - this._timer = setInterval( - () => { - const size = this._buffer.length < flushSize? this._buffer.length : flushSize; - const events = []; - for (let i = 0; i < size; i += 1) { - const params = this._buffer.shift(); - events.push(params); - } - that._sendFromBuffer(events); - }, - flushInterval - ); - } - - /** - * get the category of the plugin - */ - public getCategory(): string { - return 'Analytics'; - } - - /** - * get provider name of the plugin - */ - public getProviderName(): string { - return 'AWSKinesis'; - } - - /** - * configure the plugin - * @param {Object} config - configuration - */ - public configure(config): object { - logger.debug('configure Analytics', config); - const conf = config? config : {}; - this._config = Object.assign({}, this._config, conf); - - this._setupTimer(); - return this._config; - } - - /** - * record an event - * @param {Object} params - the params of an event - */ - public async record(params): Promise { - const credentials = await this._getCredentials(); - if (!credentials) return Promise.resolve(false); - - Object.assign(params, { config: this._config, credentials }); - - return this._putToBuffer(params); - } - - public updateEndpoint(params) { - logger.debug('updateEndpoint is not implemented in Kinesis provider'); - return Promise.resolve(true); - } - - /** - * @private - * @param params - params for the event recording - * Put events into buffer - */ - private _putToBuffer(params) { - if (this._buffer.length < BUFFER_SIZE) { - this._buffer.push(params); - return Promise.resolve(true); - } else { - logger.debug('exceed analytics events buffer size'); - return Promise.reject(false); - } - } - - private _sendFromBuffer(events) { - // collapse events by credentials - // events = [ {params} ] - const eventsGroups = []; - let preCred = null; - let group = []; - for (let i = 0; i < events.length; i += 1) { - const cred = events[i].credentials; - if (i === 0) { - group.push(events[i]); - preCred = cred; - } else { - if (cred.sessionToken === preCred.sessionToken && cred.identityId === preCred.identityId) { - logger.debug('no change for cred, put event in the same group'); - group.push(events[i]); - } else { - eventsGroups.push(group); - group = []; - group.push(events[i]); - preCred = cred; - } - } - } - eventsGroups.push(group); - - eventsGroups.map(evts => { - this._sendEvents(evts); - }); - } - - private _sendEvents(group) { - if (group.length === 0) { - // logger.debug('events array is empty, directly return'); - return; - } - - const { config, credentials } = group[0]; - - const initClients = this._init(config, credentials); - if (!initClients) return false; - - const records = {}; - - group.map(params => { - // spit by streamName - const evt = params.event; - const { streamName } = evt; - if (records[streamName] === undefined) { - records[streamName] = []; - } - - const Data = JSON.stringify(evt.data); - const PartitionKey = evt.partitionKey || ('partition-' + credentials.identityId); - const record = { Data, PartitionKey }; - records[streamName].push(record); - }); - - Object.keys(records).map(streamName => { - logger.debug('putting records to kinesis with records', records[streamName]); - this._kinesis.putRecords( - { - Records: records[streamName], - StreamName: streamName - }, - (err, data)=> { - if (err) logger.debug('Failed to upload records to Kinesis', err); - else logger.debug('Upload records to stream', streamName); - } - ); - }); - } - - private _init(config, credentials) { - logger.debug('init clients'); - - if (this._kinesis - && this._config.credentials - && this._config.credentials.sessionToken === credentials.sessionToken - && this._config.credentials.identityId === credentials.identityId) { - logger.debug('no change for analytics config, directly return from init'); - return true; - } - - this._config.credentials = credentials; - const { region } = config; - logger.debug('initialize kinesis with credentials', credentials); - this._kinesis = new Kinesis({ - apiVersion: '2013-12-02', - region, - credentials - }); - - return true; - } - - /** - * @private - * check if current credentials exists - */ - private _getCredentials() { - const that = this; - return Credentials.get() - .then(credentials => { - if (!credentials) return null; - logger.debug('set credentials for analytics', that._config.credentials); - return Credentials.shear(credentials); - }) - .catch(err => { - logger.debug('ensure credentials error', err); - return null; - }); - } + private _config; + private _kinesis; + private _buffer; + private _timer; + + constructor(config?) { + this._buffer = []; + this._config = config ? config : {}; + this._config.bufferSize = this._config.bufferSize || BUFFER_SIZE; + this._config.flushSize = this._config.flushSize || FLUSH_SIZE; + this._config.flushInterval = this._config.flushInterval || FLUSH_INTERVAL; + this._config.resendLimit = this._config.resendLimit || RESEND_LIMIT; + + // events batch + const that = this; + + // flush event buffer + this._setupTimer(); + } + + private _setupTimer() { + if (this._timer) { + clearInterval(this._timer); + } + const { flushSize, flushInterval } = this._config; + const that = this; + this._timer = setInterval(() => { + const size = + this._buffer.length < flushSize ? this._buffer.length : flushSize; + const events = []; + for (let i = 0; i < size; i += 1) { + const params = this._buffer.shift(); + events.push(params); + } + that._sendFromBuffer(events); + }, flushInterval); + } + + /** + * get the category of the plugin + */ + public getCategory(): string { + return 'Analytics'; + } + + /** + * get provider name of the plugin + */ + public getProviderName(): string { + return 'AWSKinesis'; + } + + /** + * configure the plugin + * @param {Object} config - configuration + */ + public configure(config): object { + logger.debug('configure Analytics', config); + const conf = config ? config : {}; + this._config = Object.assign({}, this._config, conf); + + this._setupTimer(); + return this._config; + } + + /** + * record an event + * @param {Object} params - the params of an event + */ + public async record(params): Promise { + const credentials = await this._getCredentials(); + if (!credentials) return Promise.resolve(false); + + Object.assign(params, { config: this._config, credentials }); + + return this._putToBuffer(params); + } + + public updateEndpoint(params) { + logger.debug('updateEndpoint is not implemented in Kinesis provider'); + return Promise.resolve(true); + } + + /** + * @private + * @param params - params for the event recording + * Put events into buffer + */ + private _putToBuffer(params) { + if (this._buffer.length < BUFFER_SIZE) { + this._buffer.push(params); + return Promise.resolve(true); + } else { + logger.debug('exceed analytics events buffer size'); + return Promise.reject(false); + } + } + + private _sendFromBuffer(events) { + // collapse events by credentials + // events = [ {params} ] + const eventsGroups = []; + let preCred = null; + let group = []; + for (let i = 0; i < events.length; i += 1) { + const cred = events[i].credentials; + if (i === 0) { + group.push(events[i]); + preCred = cred; + } else { + if ( + cred.sessionToken === preCred.sessionToken && + cred.identityId === preCred.identityId + ) { + logger.debug('no change for cred, put event in the same group'); + group.push(events[i]); + } else { + eventsGroups.push(group); + group = []; + group.push(events[i]); + preCred = cred; + } + } + } + eventsGroups.push(group); + + eventsGroups.map(evts => { + this._sendEvents(evts); + }); + } + + private _sendEvents(group) { + if (group.length === 0) { + // logger.debug('events array is empty, directly return'); + return; + } + + const { config, credentials } = group[0]; + + const initClients = this._init(config, credentials); + if (!initClients) return false; + + const records = {}; + + group.map(params => { + // spit by streamName + const evt = params.event; + const { streamName } = evt; + if (records[streamName] === undefined) { + records[streamName] = []; + } + + const Data = JSON.stringify(evt.data); + const PartitionKey = + evt.partitionKey || 'partition-' + credentials.identityId; + const record = { Data, PartitionKey }; + records[streamName].push(record); + }); + + Object.keys(records).map(streamName => { + logger.debug( + 'putting records to kinesis with records', + records[streamName] + ); + this._kinesis.putRecords( + { + Records: records[streamName], + StreamName: streamName, + }, + (err, data) => { + if (err) logger.debug('Failed to upload records to Kinesis', err); + else logger.debug('Upload records to stream', streamName); + } + ); + }); + } + + private _init(config, credentials) { + logger.debug('init clients'); + + if ( + this._kinesis && + this._config.credentials && + this._config.credentials.sessionToken === credentials.sessionToken && + this._config.credentials.identityId === credentials.identityId + ) { + logger.debug('no change for analytics config, directly return from init'); + return true; + } + + this._config.credentials = credentials; + const { region } = config; + logger.debug('initialize kinesis with credentials', credentials); + this._kinesis = new Kinesis({ + apiVersion: '2013-12-02', + region, + credentials, + }); + + return true; + } + + /** + * @private + * check if current credentials exists + */ + private _getCredentials() { + const that = this; + return Credentials.get() + .then(credentials => { + if (!credentials) return null; + logger.debug('set credentials for analytics', that._config.credentials); + return Credentials.shear(credentials); + }) + .catch(err => { + logger.debug('ensure credentials error', err); + return null; + }); + } } diff --git a/packages/analytics/src/Providers/AWSPinpointProvider.ts b/packages/analytics/src/Providers/AWSPinpointProvider.ts index a88c5fbde6a..319fa1145dd 100644 --- a/packages/analytics/src/Providers/AWSPinpointProvider.ts +++ b/packages/analytics/src/Providers/AWSPinpointProvider.ts @@ -12,13 +12,13 @@ */ import { - ConsoleLogger as Logger, - ClientDevice, - Platform, - Credentials, - Signer, - JS, - Hub + ConsoleLogger as Logger, + ClientDevice, + Platform, + Credentials, + Signer, + JS, + Hub, } from '@aws-amplify/core'; import * as MobileAnalytics from 'aws-sdk/clients/mobileanalytics'; import * as Pinpoint from 'aws-sdk/clients/pinpoint'; @@ -28,565 +28,628 @@ import Cache from '@aws-amplify/cache'; import { AnalyticsProvider, PromiseHandlers } from '../types'; import { v1 as uuid } from 'uuid'; -const AMPLIFY_SYMBOL = ((typeof Symbol !== 'undefined' && typeof Symbol.for === 'function') ? - Symbol.for('amplify_default') : '@@amplify_default') as Symbol; +const AMPLIFY_SYMBOL = (typeof Symbol !== 'undefined' && +typeof Symbol.for === 'function' + ? Symbol.for('amplify_default') + : '@@amplify_default') as Symbol; const dispatchAnalyticsEvent = (event, data) => { - Hub.dispatch('analytics', { event, data }, 'Analytics', AMPLIFY_SYMBOL); + Hub.dispatch('analytics', { event, data }, 'Analytics', AMPLIFY_SYMBOL); }; const logger = new Logger('AWSPinpointProvider'); const RETRYABLE_CODES = [429, 500]; const ACCEPTED_CODES = [202]; -const MOBILE_SERVICE_NAME = "mobiletargeting"; +const MOBILE_SERVICE_NAME = 'mobiletargeting'; // events buffer const BUFFER_SIZE = 1000; const FLUSH_SIZE = 100; -const FLUSH_INTERVAL = 5*1000; // 5s +const FLUSH_INTERVAL = 5 * 1000; // 5s const RESEND_LIMIT = 5; // params: { event: {name: , .... }, timeStamp, config, resendLimit } export default class AWSPinpointProvider implements AnalyticsProvider { - static category = 'Analytics'; - static providerName = 'AWSPinpoint'; - - private _config; - private mobileAnalytics; - private pinpointClient; - private _sessionId; - private _sessionStartTimestamp; - private _buffer; - private _clientInfo; - private _timer; - private _endpointGenerating = true; - - constructor(config?) { - this._buffer = []; - this._config = config? config : {}; - this._config.bufferSize = this._config.bufferSize || BUFFER_SIZE; - this._config.flushSize = this._config.flushSize || FLUSH_SIZE; - this._config.flushInterval = this._config.flushInterval || FLUSH_INTERVAL; - this._config.resendLimit = this._config.resendLimit || RESEND_LIMIT; - this._clientInfo = ClientDevice.clientInfo(); - } - - private _setupTimer() { - if (this._timer) { - clearInterval(this._timer); - } - const { flushSize, flushInterval } = this._config; - const that = this; - this._timer = setInterval( - () => { - const size = this._buffer.length < flushSize? this._buffer.length : flushSize; - for (let i = 0; i < size; i += 1) { - const { params, handlers } = this._buffer.shift(); - that._send(params, handlers); - // If this is the first request sent by Analytics module, we should stop sending remaining requests - // to prevent race condition of updating one endpoint when it's being created in the backend - if (this._endpointGenerating) break; - } - }, - flushInterval - ); - } - - /** - * @private - * @param params - params for the event recording - * Put events into buffer - */ - private _putToBuffer(params, handlers) { - const { bufferSize } = this._config; - if (this._buffer.length < bufferSize) { - this._buffer.push({params, handlers}); - } else { - logger.debug('exceed analytics events buffer size'); - return handlers.reject(new Error('Exceed the size of analytics events buffer')); - } - } - - /** - * get the category of the plugin - */ - getCategory(): string { - return AWSPinpointProvider.category; - } - - /** - * get provider name of the plugin - */ - getProviderName(): string { - return AWSPinpointProvider.providerName; - } - - /** - * configure the plugin - * @param {Object} config - configuration - */ - public configure(config): object { - logger.debug('configure Analytics', config); - const conf = config? config : {}; - this._config = Object.assign({}, this._config, conf); - - if (this._config['appId'] && !this._config['disabled']) { - if (!this._config['endpointId']) { - const cacheKey = this.getProviderName() + '_' + this._config['appId']; - this._getEndpointId(cacheKey).then(endpointId => { - logger.debug('setting endpoint id from the cache', endpointId); - this._config['endpointId'] = endpointId; - dispatchAnalyticsEvent('pinpointProvider_configured', null); - }).catch(e => { - logger.debug('Failed to generate endpointId', e); - }); - } else { - dispatchAnalyticsEvent('pinpointProvider_configured', null); - } - this._setupTimer(); - } else { - if (this._timer) { clearInterval(this._timer); } - } - return this._config; - } - - /** - * record an event - * @param {Object} params - the params of an event - */ - public async record(params, handlers: PromiseHandlers) { - const credentials = await this._getCredentials(); - if (!credentials || !this._config['appId'] || !this._config['region']){ - logger.debug('cannot send events without credentials, applicationId or region'); - return handlers.reject(new Error('No credentials, applicationId or region')); - } - const timestamp = new Date().getTime(); - // attach the session and eventId - this._generateSession(params); - params.event.eventId = uuid(); - - Object.assign(params, { timestamp, config: this._config, credentials }); - if (params.event.immediate) { - return this._send(params, handlers); - } else { - this._putToBuffer(params, handlers); - } - } - - private _generateSession(params) { - this._sessionId = this._sessionId || uuid(); - const { event } = params; - - switch (event.name) { - case '_session.start': - // refresh the session id and session start time - this._sessionStartTimestamp = new Date().getTime(); - this._sessionId = uuid(); - event.session = { - Id: this._sessionId, - StartTimestamp: new Date(this._sessionStartTimestamp).toISOString() - }; - break; - case '_session.stop': - const stopTimestamp = new Date().getTime(); - this._sessionStartTimestamp = this._sessionStartTimestamp || new Date().getTime(); - this._sessionId = this._sessionId || uuid(); - event.session = { - Id: this._sessionId, - Duration: stopTimestamp - this._sessionStartTimestamp, - StartTimestamp: new Date(this._sessionStartTimestamp).toISOString(), - StopTimestamp: new Date(stopTimestamp).toISOString() - }; - this._sessionId = undefined; - this._sessionStartTimestamp = undefined; - break; - default: - this._sessionStartTimestamp = this._sessionStartTimestamp || new Date().getTime(); - this._sessionId = this._sessionId || uuid(); - event.session = { - Id: this._sessionId, - StartTimestamp: new Date(this._sessionStartTimestamp).toISOString() - }; - break; - } - } - - private async _send(params, handlers) { - const { event, config } = params; - - switch (event.name) { - case '_update_endpoint': - return this._updateEndpoint(params, handlers); - case '_session.stop': - return this._pinpointSendStopSession(params, handlers); - default: - return this._record(params, handlers); - } - } - - private _generateBatchItemContext(params) { - const { event, timestamp, config, credentials } = params; - const { name, attributes, metrics, eventId, session } = event; - const { appId, endpointId } = config; - - const endpointContext = {}; - - const eventParams = { - ApplicationId: appId, - EventsRequest: { - BatchItem: {} - } - }; - - eventParams.EventsRequest.BatchItem[endpointId] = {}; - const endpointObj = eventParams.EventsRequest.BatchItem[endpointId]; - endpointObj['Endpoint'] = endpointContext; - endpointObj['Events'] = {}; - endpointObj['Events'][eventId] = { - EventType: name, - Timestamp: new Date(timestamp).toISOString(), - Attributes: attributes, - Metrics: metrics, - Session: session - }; - - return eventParams; - } - - private async _pinpointPutEvents(params, handlers) { - const { event : { eventId }, config : { endpointId } } = params; - const eventParams = this._generateBatchItemContext(params); - - const request = this.pinpointClient.putEvents(eventParams); - // in order to keep backward compatiblity - // we are using a legacy api: /apps/{appid}/events/legacy - // so that users don't need to update their IAM Policy - // will use the formal one in the next break release - request.on('build', function() { - request.httpRequest.path = request.httpRequest.path + '/legacy'; - }); - - request.send((err, data) => { - if (err) { - logger.error('record event failed. ', err); - logger.warn( - 'If you have not updated your Pinpoint IAM Policy' + - ' with the Action: \"mobiletargeting:PutEvents\" yet, please do it.' + - ' This action is not necessary for now' + - ' but in order to avoid breaking changes in the future,' + - ' please update it as soon as possible.' - ); - return handlers.reject(err); - } - else { - const { - EventsResponse : { - Results : { - [endpointId] : { - EventsItemResponse: { - [eventId]: { - StatusCode, - Message - } - } - } - } - } - } = data; - if ( ACCEPTED_CODES.includes(StatusCode)) { - this._endpointGenerating = false; - logger.debug('record event success. ', data); - return handlers.resolve(data); - } else { - if (RETRYABLE_CODES.includes(StatusCode)) { - this._retry(params, handlers); - } else { - logger.error(`Event ${eventId} is not accepted, the error is ${Message}`); - return handlers.reject(data); - } - } - } - }); - } - - private _pinpointSendStopSession(params, handlers): Promise { - const eventParams = this._generateBatchItemContext(params); - - const { region } = this._config; - const { ApplicationId, EventsRequest } = eventParams; - - const accessInfo = { - secret_key: this._config.credentials.secretAccessKey, - access_key: this._config.credentials.accessKeyId, - session_token: this._config.credentials.sessionToken, - }; - - const url = `https://pinpoint.${region}.amazonaws.com/v1/apps/${ApplicationId}/events`; - const body = JSON.stringify(EventsRequest); - const method = 'POST'; - - const request = { - url, - body, - method, - }; - - const serviceInfo = { region, service: MOBILE_SERVICE_NAME }; - - const requestUrl: string = Signer.signUrl(request, accessInfo, serviceInfo, null); - - const success: boolean = navigator.sendBeacon(requestUrl, body); - - if (success) { - return handlers.resolve('sendBeacon success'); - } - return handlers.reject('sendBeacon failure'); - } - - private _retry(params, handlers) { - const { config : { resendLimit } } = params; - // For backward compatibility - params.resendLimit = typeof params.resendLimit === 'number' ? - params.resendLimit : resendLimit; - if (params.resendLimit-- > 0) { - logger.debug( - `resending event ${params.eventName} with ${params.resendLimit} retry times left`); - this._putToBuffer(params, handlers); - } else { - logger.debug(`retry times used up for event ${params.eventName}`); - } - } - - private async _record(params, handlers) { - // credentials updated - const { event, timestamp, config, credentials } = params; - this._initClients(config, credentials); - return this._pinpointPutEvents(params, handlers); - } - - private async _updateEndpoint(params, handlers) { - // credentials updated - const { timestamp, config, credentials, event } = params; - const { appId, region, endpointId } = config; - - this._initClients(config, credentials); - - const request = this._endpointRequest( - config, - JS.transferKeyToLowerCase(event, [], ['attributes', 'userAttributes', 'Attributes', 'UserAttributes']) - ); - const update_params = { - ApplicationId: appId, - EndpointId: endpointId, - EndpointRequest: request - }; - - const that = this; - logger.debug('updateEndpoint with params: ', update_params); - - that.pinpointClient.updateEndpoint(update_params, (err, data) => { - if (err) { - logger.debug('updateEndpoint failed', err); - if (err.message.startsWith('Exceeded maximum endpoint per user count')) { - this._removeUnusedEndpoints(appId, request.User.UserId) - .then(() => { - logger.debug('Remove the unused endpoints successfully'); - this._retry(params, handlers); - }).catch(e => { - logger.warn(`Failed to remove unused endpoints with error: ${e}`); - logger.warn(`Please ensure you have updated your Pinpoint IAM Policy ` + - `with the Action: "mobiletargeting:GetUserEndpoints" ` + - `in order to get endpoints info of the user`); - return handlers.reject(err); - }); - } - else return handlers.reject(err); - } else { - logger.debug('updateEndpoint success', data); - this._endpointGenerating = false; - return handlers.resolve(data); - } - }); - } - - private async _removeUnusedEndpoints(appId, userId) { - return new Promise((res, rej) => { - this.pinpointClient.getUserEndpoints( - { - ApplicationId: appId, - UserId: userId - }, - (err, data) => { - if (err) { - logger.debug(`Failed to get endpoints associated with the userId: ${userId} with error`, err); - return rej(err); - } - const endpoints = data.EndpointsResponse.Item; - logger.debug(`get endpoints associated with the userId: ${userId} with data`, endpoints); - let endpointToBeDeleted = endpoints[0]; - for (let i = 1; i < endpoints.length; i++) { - const timeStamp1 = Date.parse(endpointToBeDeleted['EffectiveDate']); - const timeStamp2 = Date.parse(endpoints[i]['EffectiveDate']); - // delete the one with invalid effective date - if (isNaN(timeStamp1)) break; - if (isNaN(timeStamp2)) { endpointToBeDeleted = endpoints[i]; break; } - - if (timeStamp2 < timeStamp1) { - endpointToBeDeleted = endpoints[i]; - } - } - // update the endpoint's user id with an empty string - const update_params = { - ApplicationId: appId, - EndpointId: endpointToBeDeleted['Id'], - EndpointRequest: { - User: { - UserId: '' - } - } - }; - this.pinpointClient.updateEndpoint( - update_params, - (err, data) => { - if (err) { - logger.debug('Failed to update the endpoint', err); - return rej(err); - } - logger.debug('The old endpoint is updated with an empty string for user id'); - return res(data); - }); - }); - }); - - } - - /** - * @private - * @param config - * Init the clients - */ - private async _initClients(config, credentials) { - logger.debug('init clients'); - - if (this.mobileAnalytics - && this.pinpointClient - && this._config.credentials - && this._config.credentials.sessionToken === credentials.sessionToken - && this._config.credentials.identityId === credentials.identityId) { - logger.debug('no change for aws credentials, directly return from init'); - return; - } - - this._config.credentials = credentials; - const { region } = config; - logger.debug('init clients with credentials', credentials); - this.mobileAnalytics = new MobileAnalytics({ credentials, region }); - this.pinpointClient = new Pinpoint({ region, credentials }); - - if (Platform.isReactNative) { - this.pinpointClient.customizeRequests(function(request) { - request.on('build', function(req) { - req.httpRequest.headers['user-agent'] = Platform.userAgent; - }); - }); - } - - } - - private async _getEndpointId(cacheKey) { - // try to get from cache - let endpointId = await Cache.getItem(cacheKey); - logger.debug('endpointId from cache', endpointId, 'type', typeof endpointId); - if (!endpointId) { - endpointId = uuid(); - Cache.setItem(cacheKey, endpointId); - } - return endpointId; - } - - /** - * EndPoint request - * @return {Object} - The request of updating endpoint - */ - private _endpointRequest(config, event) { - const { credentials } = config; - const clientInfo = this._clientInfo || {}; - const clientContext = config.clientContext || {}; - // for now we have three different ways for default endpoint configurations - // clientInfo - // clientContext (deprecated) - // config.endpoint - const defaultEndpointConfig = config.endpoint || {}; - const demographicByClientInfo = { - appVersion: clientInfo.appVersion, - make: clientInfo.make, - model: clientInfo.model, - modelVersion: clientInfo.version, - platform: clientInfo.platform - }; - // for backward compatibility - const { - clientId, - appTitle, - appVersionName, - appVersionCode, - appPackageName, - ...demographicByClientContext - } = clientContext; - const channelType = event.address? ((clientInfo.platform === 'android') ? 'GCM' : 'APNS') : undefined; - const tmp = { - channelType, - requestId: uuid(), - effectiveDate:new Date().toISOString(), - ...defaultEndpointConfig, - ...event, - attributes: { - ...defaultEndpointConfig.attributes, - ...event.attributes - }, - demographic: { - ...demographicByClientInfo, - ...demographicByClientContext, - ...defaultEndpointConfig.demographic, - ...event.demographic - }, - location: { - ...defaultEndpointConfig.location, - ...event.location - }, - metrics: { - ...defaultEndpointConfig.metrics, - ...event.metrics - }, - user: { - userId: event.userId || defaultEndpointConfig.userId || credentials.identityId, - userAttributes: { - ...defaultEndpointConfig.userAttributes, - ...event.userAttributes - } - } - }; - - // eliminate unnecessary params - const { userId, userAttributes, name, session, eventId, immediate, ...ret } = tmp; - return JS.transferKeyToUpperCase(ret, [], ['metrics', 'userAttributes', 'attributes']); - } - - /** - * @private - * check if current credentials exists - */ - private _getCredentials() { - const that = this; - return Credentials.get() - .then(credentials => { - if (!credentials) return null; - logger.debug('set credentials for analytics', credentials); - return Credentials.shear(credentials); - }) - .catch(err => { - logger.debug('ensure credentials error', err); - return null; - }); - } + static category = 'Analytics'; + static providerName = 'AWSPinpoint'; + + private _config; + private mobileAnalytics; + private pinpointClient; + private _sessionId; + private _sessionStartTimestamp; + private _buffer; + private _clientInfo; + private _timer; + private _endpointGenerating = true; + + constructor(config?) { + this._buffer = []; + this._config = config ? config : {}; + this._config.bufferSize = this._config.bufferSize || BUFFER_SIZE; + this._config.flushSize = this._config.flushSize || FLUSH_SIZE; + this._config.flushInterval = this._config.flushInterval || FLUSH_INTERVAL; + this._config.resendLimit = this._config.resendLimit || RESEND_LIMIT; + this._clientInfo = ClientDevice.clientInfo(); + } + + private _setupTimer() { + if (this._timer) { + clearInterval(this._timer); + } + const { flushSize, flushInterval } = this._config; + const that = this; + this._timer = setInterval(() => { + const size = + this._buffer.length < flushSize ? this._buffer.length : flushSize; + for (let i = 0; i < size; i += 1) { + const { params, handlers } = this._buffer.shift(); + that._send(params, handlers); + // If this is the first request sent by Analytics module, we should stop sending remaining requests + // to prevent race condition of updating one endpoint when it's being created in the backend + if (this._endpointGenerating) break; + } + }, flushInterval); + } + + /** + * @private + * @param params - params for the event recording + * Put events into buffer + */ + private _putToBuffer(params, handlers) { + const { bufferSize } = this._config; + if (this._buffer.length < bufferSize) { + this._buffer.push({ params, handlers }); + } else { + logger.debug('exceed analytics events buffer size'); + return handlers.reject( + new Error('Exceed the size of analytics events buffer') + ); + } + } + + /** + * get the category of the plugin + */ + getCategory(): string { + return AWSPinpointProvider.category; + } + + /** + * get provider name of the plugin + */ + getProviderName(): string { + return AWSPinpointProvider.providerName; + } + + /** + * configure the plugin + * @param {Object} config - configuration + */ + public configure(config): object { + logger.debug('configure Analytics', config); + const conf = config ? config : {}; + this._config = Object.assign({}, this._config, conf); + + if (this._config['appId'] && !this._config['disabled']) { + if (!this._config['endpointId']) { + const cacheKey = this.getProviderName() + '_' + this._config['appId']; + this._getEndpointId(cacheKey) + .then(endpointId => { + logger.debug('setting endpoint id from the cache', endpointId); + this._config['endpointId'] = endpointId; + dispatchAnalyticsEvent('pinpointProvider_configured', null); + }) + .catch(e => { + logger.debug('Failed to generate endpointId', e); + }); + } else { + dispatchAnalyticsEvent('pinpointProvider_configured', null); + } + this._setupTimer(); + } else { + if (this._timer) { + clearInterval(this._timer); + } + } + return this._config; + } + + /** + * record an event + * @param {Object} params - the params of an event + */ + public async record(params, handlers: PromiseHandlers) { + const credentials = await this._getCredentials(); + if (!credentials || !this._config['appId'] || !this._config['region']) { + logger.debug( + 'cannot send events without credentials, applicationId or region' + ); + return handlers.reject( + new Error('No credentials, applicationId or region') + ); + } + const timestamp = new Date().getTime(); + // attach the session and eventId + this._generateSession(params); + params.event.eventId = uuid(); + + Object.assign(params, { timestamp, config: this._config, credentials }); + if (params.event.immediate) { + return this._send(params, handlers); + } else { + this._putToBuffer(params, handlers); + } + } + + private _generateSession(params) { + this._sessionId = this._sessionId || uuid(); + const { event } = params; + + switch (event.name) { + case '_session.start': + // refresh the session id and session start time + this._sessionStartTimestamp = new Date().getTime(); + this._sessionId = uuid(); + event.session = { + Id: this._sessionId, + StartTimestamp: new Date(this._sessionStartTimestamp).toISOString(), + }; + break; + case '_session.stop': + const stopTimestamp = new Date().getTime(); + this._sessionStartTimestamp = + this._sessionStartTimestamp || new Date().getTime(); + this._sessionId = this._sessionId || uuid(); + event.session = { + Id: this._sessionId, + Duration: stopTimestamp - this._sessionStartTimestamp, + StartTimestamp: new Date(this._sessionStartTimestamp).toISOString(), + StopTimestamp: new Date(stopTimestamp).toISOString(), + }; + this._sessionId = undefined; + this._sessionStartTimestamp = undefined; + break; + default: + this._sessionStartTimestamp = + this._sessionStartTimestamp || new Date().getTime(); + this._sessionId = this._sessionId || uuid(); + event.session = { + Id: this._sessionId, + StartTimestamp: new Date(this._sessionStartTimestamp).toISOString(), + }; + break; + } + } + + private async _send(params, handlers) { + const { event, config } = params; + + switch (event.name) { + case '_update_endpoint': + return this._updateEndpoint(params, handlers); + case '_session.stop': + return this._pinpointSendStopSession(params, handlers); + default: + return this._record(params, handlers); + } + } + + private _generateBatchItemContext(params) { + const { event, timestamp, config, credentials } = params; + const { name, attributes, metrics, eventId, session } = event; + const { appId, endpointId } = config; + + const endpointContext = {}; + + const eventParams = { + ApplicationId: appId, + EventsRequest: { + BatchItem: {}, + }, + }; + + eventParams.EventsRequest.BatchItem[endpointId] = {}; + const endpointObj = eventParams.EventsRequest.BatchItem[endpointId]; + endpointObj['Endpoint'] = endpointContext; + endpointObj['Events'] = {}; + endpointObj['Events'][eventId] = { + EventType: name, + Timestamp: new Date(timestamp).toISOString(), + Attributes: attributes, + Metrics: metrics, + Session: session, + }; + + return eventParams; + } + + private async _pinpointPutEvents(params, handlers) { + const { + event: { eventId }, + config: { endpointId }, + } = params; + const eventParams = this._generateBatchItemContext(params); + + const request = this.pinpointClient.putEvents(eventParams); + // in order to keep backward compatiblity + // we are using a legacy api: /apps/{appid}/events/legacy + // so that users don't need to update their IAM Policy + // will use the formal one in the next break release + request.on('build', function() { + request.httpRequest.path = request.httpRequest.path + '/legacy'; + }); + + request.send((err, data) => { + if (err) { + logger.error('record event failed. ', err); + logger.warn( + 'If you have not updated your Pinpoint IAM Policy' + + ' with the Action: "mobiletargeting:PutEvents" yet, please do it.' + + ' This action is not necessary for now' + + ' but in order to avoid breaking changes in the future,' + + ' please update it as soon as possible.' + ); + return handlers.reject(err); + } else { + const { + EventsResponse: { + Results: { + [endpointId]: { + EventsItemResponse: { + [eventId]: { StatusCode, Message }, + }, + }, + }, + }, + } = data; + if (ACCEPTED_CODES.includes(StatusCode)) { + this._endpointGenerating = false; + logger.debug('record event success. ', data); + return handlers.resolve(data); + } else { + if (RETRYABLE_CODES.includes(StatusCode)) { + this._retry(params, handlers); + } else { + logger.error( + `Event ${eventId} is not accepted, the error is ${Message}` + ); + return handlers.reject(data); + } + } + } + }); + } + + private _pinpointSendStopSession(params, handlers): Promise { + const eventParams = this._generateBatchItemContext(params); + + const { region } = this._config; + const { ApplicationId, EventsRequest } = eventParams; + + const accessInfo = { + secret_key: this._config.credentials.secretAccessKey, + access_key: this._config.credentials.accessKeyId, + session_token: this._config.credentials.sessionToken, + }; + + const url = `https://pinpoint.${region}.amazonaws.com/v1/apps/${ApplicationId}/events`; + const body = JSON.stringify(EventsRequest); + const method = 'POST'; + + const request = { + url, + body, + method, + }; + + const serviceInfo = { region, service: MOBILE_SERVICE_NAME }; + + const requestUrl: string = Signer.signUrl( + request, + accessInfo, + serviceInfo, + null + ); + + const success: boolean = navigator.sendBeacon(requestUrl, body); + + if (success) { + return handlers.resolve('sendBeacon success'); + } + return handlers.reject('sendBeacon failure'); + } + + private _retry(params, handlers) { + const { + config: { resendLimit }, + } = params; + // For backward compatibility + params.resendLimit = + typeof params.resendLimit === 'number' ? params.resendLimit : resendLimit; + if (params.resendLimit-- > 0) { + logger.debug( + `resending event ${params.eventName} with ${params.resendLimit} retry times left` + ); + this._putToBuffer(params, handlers); + } else { + logger.debug(`retry times used up for event ${params.eventName}`); + } + } + + private async _record(params, handlers) { + // credentials updated + const { event, timestamp, config, credentials } = params; + this._initClients(config, credentials); + return this._pinpointPutEvents(params, handlers); + } + + private async _updateEndpoint(params, handlers) { + // credentials updated + const { timestamp, config, credentials, event } = params; + const { appId, region, endpointId } = config; + + this._initClients(config, credentials); + + const request = this._endpointRequest( + config, + JS.transferKeyToLowerCase( + event, + [], + ['attributes', 'userAttributes', 'Attributes', 'UserAttributes'] + ) + ); + const update_params = { + ApplicationId: appId, + EndpointId: endpointId, + EndpointRequest: request, + }; + + const that = this; + logger.debug('updateEndpoint with params: ', update_params); + + that.pinpointClient.updateEndpoint(update_params, (err, data) => { + if (err) { + logger.debug('updateEndpoint failed', err); + if ( + err.message.startsWith('Exceeded maximum endpoint per user count') + ) { + this._removeUnusedEndpoints(appId, request.User.UserId) + .then(() => { + logger.debug('Remove the unused endpoints successfully'); + this._retry(params, handlers); + }) + .catch(e => { + logger.warn(`Failed to remove unused endpoints with error: ${e}`); + logger.warn( + `Please ensure you have updated your Pinpoint IAM Policy ` + + `with the Action: "mobiletargeting:GetUserEndpoints" ` + + `in order to get endpoints info of the user` + ); + return handlers.reject(err); + }); + } else return handlers.reject(err); + } else { + logger.debug('updateEndpoint success', data); + this._endpointGenerating = false; + return handlers.resolve(data); + } + }); + } + + private async _removeUnusedEndpoints(appId, userId) { + return new Promise((res, rej) => { + this.pinpointClient.getUserEndpoints( + { + ApplicationId: appId, + UserId: userId, + }, + (err, data) => { + if (err) { + logger.debug( + `Failed to get endpoints associated with the userId: ${userId} with error`, + err + ); + return rej(err); + } + const endpoints = data.EndpointsResponse.Item; + logger.debug( + `get endpoints associated with the userId: ${userId} with data`, + endpoints + ); + let endpointToBeDeleted = endpoints[0]; + for (let i = 1; i < endpoints.length; i++) { + const timeStamp1 = Date.parse(endpointToBeDeleted['EffectiveDate']); + const timeStamp2 = Date.parse(endpoints[i]['EffectiveDate']); + // delete the one with invalid effective date + if (isNaN(timeStamp1)) break; + if (isNaN(timeStamp2)) { + endpointToBeDeleted = endpoints[i]; + break; + } + + if (timeStamp2 < timeStamp1) { + endpointToBeDeleted = endpoints[i]; + } + } + // update the endpoint's user id with an empty string + const update_params = { + ApplicationId: appId, + EndpointId: endpointToBeDeleted['Id'], + EndpointRequest: { + User: { + UserId: '', + }, + }, + }; + this.pinpointClient.updateEndpoint(update_params, (err, data) => { + if (err) { + logger.debug('Failed to update the endpoint', err); + return rej(err); + } + logger.debug( + 'The old endpoint is updated with an empty string for user id' + ); + return res(data); + }); + } + ); + }); + } + + /** + * @private + * @param config + * Init the clients + */ + private async _initClients(config, credentials) { + logger.debug('init clients'); + + if ( + this.mobileAnalytics && + this.pinpointClient && + this._config.credentials && + this._config.credentials.sessionToken === credentials.sessionToken && + this._config.credentials.identityId === credentials.identityId + ) { + logger.debug('no change for aws credentials, directly return from init'); + return; + } + + this._config.credentials = credentials; + const { region } = config; + logger.debug('init clients with credentials', credentials); + this.mobileAnalytics = new MobileAnalytics({ credentials, region }); + this.pinpointClient = new Pinpoint({ region, credentials }); + + if (Platform.isReactNative) { + this.pinpointClient.customizeRequests(function(request) { + request.on('build', function(req) { + req.httpRequest.headers['user-agent'] = Platform.userAgent; + }); + }); + } + } + + private async _getEndpointId(cacheKey) { + // try to get from cache + let endpointId = await Cache.getItem(cacheKey); + logger.debug( + 'endpointId from cache', + endpointId, + 'type', + typeof endpointId + ); + if (!endpointId) { + endpointId = uuid(); + Cache.setItem(cacheKey, endpointId); + } + return endpointId; + } + + /** + * EndPoint request + * @return {Object} - The request of updating endpoint + */ + private _endpointRequest(config, event) { + const { credentials } = config; + const clientInfo = this._clientInfo || {}; + const clientContext = config.clientContext || {}; + // for now we have three different ways for default endpoint configurations + // clientInfo + // clientContext (deprecated) + // config.endpoint + const defaultEndpointConfig = config.endpoint || {}; + const demographicByClientInfo = { + appVersion: clientInfo.appVersion, + make: clientInfo.make, + model: clientInfo.model, + modelVersion: clientInfo.version, + platform: clientInfo.platform, + }; + // for backward compatibility + const { + clientId, + appTitle, + appVersionName, + appVersionCode, + appPackageName, + ...demographicByClientContext + } = clientContext; + const channelType = event.address + ? clientInfo.platform === 'android' + ? 'GCM' + : 'APNS' + : undefined; + const tmp = { + channelType, + requestId: uuid(), + effectiveDate: new Date().toISOString(), + ...defaultEndpointConfig, + ...event, + attributes: { + ...defaultEndpointConfig.attributes, + ...event.attributes, + }, + demographic: { + ...demographicByClientInfo, + ...demographicByClientContext, + ...defaultEndpointConfig.demographic, + ...event.demographic, + }, + location: { + ...defaultEndpointConfig.location, + ...event.location, + }, + metrics: { + ...defaultEndpointConfig.metrics, + ...event.metrics, + }, + user: { + userId: + event.userId || + defaultEndpointConfig.userId || + credentials.identityId, + userAttributes: { + ...defaultEndpointConfig.userAttributes, + ...event.userAttributes, + }, + }, + }; + + // eliminate unnecessary params + const { + userId, + userAttributes, + name, + session, + eventId, + immediate, + ...ret + } = tmp; + return JS.transferKeyToUpperCase( + ret, + [], + ['metrics', 'userAttributes', 'attributes'] + ); + } + + /** + * @private + * check if current credentials exists + */ + private _getCredentials() { + const that = this; + return Credentials.get() + .then(credentials => { + if (!credentials) return null; + logger.debug('set credentials for analytics', credentials); + return Credentials.shear(credentials); + }) + .catch(err => { + logger.debug('ensure credentials error', err); + return null; + }); + } } diff --git a/packages/analytics/src/Providers/AmazonPersonalizeHelper/DataType.ts b/packages/analytics/src/Providers/AmazonPersonalizeHelper/DataType.ts index e43e28c9dab..5de21b62bae 100644 --- a/packages/analytics/src/Providers/AmazonPersonalizeHelper/DataType.ts +++ b/packages/analytics/src/Providers/AmazonPersonalizeHelper/DataType.ts @@ -13,47 +13,47 @@ import { AWS } from '@aws-amplify/core'; interface BasePayload { - userId: string; - trackingId: string; - sessionId: string; + userId: string; + trackingId: string; + sessionId: string; } type Config = { - [key: string]: string | number; + [key: string]: string | number; }; type Properties = { - [key: string]: any; + [key: string]: any; }; export interface RequestParams { - eventData: EventData; - sessionInfo: SessionInfo; - config: Config; - sentAt: number; - credentials: AWS.Credentials & AWS.CognitoIdentityCredentials; + eventData: EventData; + sessionInfo: SessionInfo; + config: Config; + sentAt: number; + credentials: AWS.Credentials & AWS.CognitoIdentityCredentials; } export interface EventData { - eventType: string; - properties: Properties; + eventType: string; + properties: Properties; } export interface SessionInfo { - userId: string; - trackingId: string; - sessionId: string; + userId: string; + trackingId: string; + sessionId: string; } export interface RecordEventPayload { - eventId: string; - eventType: string; - sentAt: number; - properties?: Properties; + eventId: string; + eventType: string; + sentAt: number; + properties?: Properties; } export interface RecordEventListPayload extends BasePayload { - eventList: RecordEventPayload[]; - config?: Config; - credentials?: AWS.Credentials & AWS.CognitoIdentityCredentials; + eventList: RecordEventPayload[]; + config?: Config; + credentials?: AWS.Credentials & AWS.CognitoIdentityCredentials; } diff --git a/packages/analytics/src/Providers/AmazonPersonalizeHelper/MediaAutoTrack.ts b/packages/analytics/src/Providers/AmazonPersonalizeHelper/MediaAutoTrack.ts index 3b707703f4a..84ce1023fd8 100644 --- a/packages/analytics/src/Providers/AmazonPersonalizeHelper/MediaAutoTrack.ts +++ b/packages/analytics/src/Providers/AmazonPersonalizeHelper/MediaAutoTrack.ts @@ -10,187 +10,199 @@ * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ -import {RequestParams, SessionInfo} from './DataType'; +import { RequestParams, SessionInfo } from './DataType'; enum HTML5_MEDIA_EVENT { - "PLAY" = "play", - "PAUSE" = "pause", - "ENDED" = "Ended" - } + 'PLAY' = 'play', + 'PAUSE' = 'pause', + 'ENDED' = 'Ended', +} enum MEDIA_TYPE { - "IFRAME" = "IFRAME", - "VIDEO" = "VIDEO", - "AUDIO" = "AUDIO" - } + 'IFRAME' = 'IFRAME', + 'VIDEO' = 'VIDEO', + 'AUDIO' = 'AUDIO', +} enum EVENT_TYPE { - "PLAY" = "Play", - "ENDED" = "Ended", - "PAUSE" = "Pause", - "TIME_WATCHED" = "TimeWatched" - } + 'PLAY' = 'Play', + 'ENDED' = 'Ended', + 'PAUSE' = 'Pause', + 'TIME_WATCHED' = 'TimeWatched', +} export class MediaAutoTrack { - private _mediaElement; - private _provider; - private _params; - private _started; - private _iframePlayer; - private eventActionMapping = { - [EVENT_TYPE.ENDED]: this.endedEventAction.bind(this), - [EVENT_TYPE.PLAY]: this.playEventAction.bind(this), - [EVENT_TYPE.PAUSE]: this.pauseEventAction.bind(this) - }; - - private _youTubeIframeLoader; - - constructor(params: RequestParams, provider) { - const { eventData } = params; - this._params = params; - this._mediaElement = document.getElementById(eventData.properties["domElementId"]); - this._started = false; - this._provider = provider; - const mediaTrackFunMapping = { - IFRAME: this._iframeMediaTracker, - VIDEO: this._html5MediaTracker, - AUDIO: this._html5MediaTracker - }; - - mediaTrackFunMapping[this._mediaElement.tagName].bind(this)(); - - this._initYoutubeFrame(); - } - - private _initYoutubeFrame() { - this._youTubeIframeLoader = { - src: 'https://www.youtube.com/iframe_api', - loading: false, - loaded: false, - listeners: [], - - load(callback) { - const _this = this; - this.listeners.push(callback); - - if (this.loaded) { - setTimeout(function() { - _this.done(); - }); - return; - } - - if (this.loading) { - return; - } - - this.loading = true; - - window['onYouTubeIframeAPIReady'] = function() { - _this.loaded = true; - _this.done(); - }; - - const script = document.createElement('script'); - script.type = 'text/javascript'; - script.src = this.src; - document.body.appendChild(script); - }, - - done() { - delete window['onYouTubeIframeAPIReady']; - - while (this.listeners.length) { - this.listeners.pop()(window['YT']); - } - } - }; - } - - private _iframeMediaTracker() : void { - const that = this; - setInterval( - function() { - if (that._started) { - that.recordEvent(MEDIA_TYPE.IFRAME , EVENT_TYPE.TIME_WATCHED); - } - }, - 3*1000 - ); - this._youTubeIframeLoader.load(function(YT) { - that._iframePlayer = new YT.Player(that._mediaElement.id, { - events: {'onStateChange': that._onPlayerStateChange.bind(that)} - }); - }); - } - - private _onPlayerStateChange(event) : void { - const iframeEventMapping = { - 0: EVENT_TYPE.ENDED, - 1: EVENT_TYPE.PLAY, - 2: EVENT_TYPE.PAUSE - }; - const eventType = iframeEventMapping[event.data]; - if (eventType) { - this.eventActionMapping[eventType](MEDIA_TYPE.IFRAME); - } - } - - private _html5MediaTracker() : void { - const that = this; - setInterval( - function() { - if (that._started) { - that.recordEvent(MEDIA_TYPE.VIDEO , EVENT_TYPE.TIME_WATCHED); - } - }, - 3*1000 - ); - this._mediaElement.addEventListener( - HTML5_MEDIA_EVENT.PLAY, - () => { - that.eventActionMapping[EVENT_TYPE.PLAY](MEDIA_TYPE.VIDEO); - }, - false - ); - this._mediaElement.addEventListener( - HTML5_MEDIA_EVENT.PAUSE, () => { that.eventActionMapping[EVENT_TYPE.PAUSE](MEDIA_TYPE.VIDEO);}, false); - - this._mediaElement.addEventListener( - HTML5_MEDIA_EVENT.ENDED, () => { that.eventActionMapping[EVENT_TYPE.ENDED](MEDIA_TYPE.VIDEO);}, false); - } - - private playEventAction(mediaType) { - this._started = true; - this.recordEvent(mediaType, EVENT_TYPE.PLAY); - } - - private pauseEventAction(mediaType) { - this._started = false; - this.recordEvent(mediaType, EVENT_TYPE.PAUSE); - } - - private endedEventAction(mediaType) { - this._started = false; - this.recordEvent(mediaType , EVENT_TYPE.ENDED); - } - - private recordEvent(mediaType : string, eventType: string) : void { - const newParams = Object.assign({}, this._params); - const { eventData } = newParams; - eventData.eventType = eventType; - if (mediaType === MEDIA_TYPE.VIDEO) { - eventData.properties.timestamp = this._mediaElement.currentTime; - eventData.properties.duration = this._mediaElement.duration; - } else { - eventData.properties.timestamp = this._financial(this._iframePlayer.getCurrentTime()); - eventData.properties.duration = this._financial(this._iframePlayer.getDuration()); - } - const percentage = parseFloat(eventData.properties.timestamp) / parseFloat(eventData.properties.duration); - eventData.properties.eventValue = Number(percentage.toFixed(4)); - delete eventData.properties.domElementId; - this._provider.putToBuffer(newParams); - } - - private _financial(x) { - return Number.parseFloat(x).toFixed(4); - } + private _mediaElement; + private _provider; + private _params; + private _started; + private _iframePlayer; + private eventActionMapping = { + [EVENT_TYPE.ENDED]: this.endedEventAction.bind(this), + [EVENT_TYPE.PLAY]: this.playEventAction.bind(this), + [EVENT_TYPE.PAUSE]: this.pauseEventAction.bind(this), + }; + + private _youTubeIframeLoader; + + constructor(params: RequestParams, provider) { + const { eventData } = params; + this._params = params; + this._mediaElement = document.getElementById( + eventData.properties['domElementId'] + ); + this._started = false; + this._provider = provider; + const mediaTrackFunMapping = { + IFRAME: this._iframeMediaTracker, + VIDEO: this._html5MediaTracker, + AUDIO: this._html5MediaTracker, + }; + + mediaTrackFunMapping[this._mediaElement.tagName].bind(this)(); + + this._initYoutubeFrame(); + } + + private _initYoutubeFrame() { + this._youTubeIframeLoader = { + src: 'https://www.youtube.com/iframe_api', + loading: false, + loaded: false, + listeners: [], + + load(callback) { + const _this = this; + this.listeners.push(callback); + + if (this.loaded) { + setTimeout(function() { + _this.done(); + }); + return; + } + + if (this.loading) { + return; + } + + this.loading = true; + + window['onYouTubeIframeAPIReady'] = function() { + _this.loaded = true; + _this.done(); + }; + + const script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = this.src; + document.body.appendChild(script); + }, + + done() { + delete window['onYouTubeIframeAPIReady']; + + while (this.listeners.length) { + this.listeners.pop()(window['YT']); + } + }, + }; + } + + private _iframeMediaTracker(): void { + const that = this; + setInterval(function() { + if (that._started) { + that.recordEvent(MEDIA_TYPE.IFRAME, EVENT_TYPE.TIME_WATCHED); + } + }, 3 * 1000); + this._youTubeIframeLoader.load(function(YT) { + that._iframePlayer = new YT.Player(that._mediaElement.id, { + events: { onStateChange: that._onPlayerStateChange.bind(that) }, + }); + }); + } + + private _onPlayerStateChange(event): void { + const iframeEventMapping = { + 0: EVENT_TYPE.ENDED, + 1: EVENT_TYPE.PLAY, + 2: EVENT_TYPE.PAUSE, + }; + const eventType = iframeEventMapping[event.data]; + if (eventType) { + this.eventActionMapping[eventType](MEDIA_TYPE.IFRAME); + } + } + + private _html5MediaTracker(): void { + const that = this; + setInterval(function() { + if (that._started) { + that.recordEvent(MEDIA_TYPE.VIDEO, EVENT_TYPE.TIME_WATCHED); + } + }, 3 * 1000); + this._mediaElement.addEventListener( + HTML5_MEDIA_EVENT.PLAY, + () => { + that.eventActionMapping[EVENT_TYPE.PLAY](MEDIA_TYPE.VIDEO); + }, + false + ); + this._mediaElement.addEventListener( + HTML5_MEDIA_EVENT.PAUSE, + () => { + that.eventActionMapping[EVENT_TYPE.PAUSE](MEDIA_TYPE.VIDEO); + }, + false + ); + + this._mediaElement.addEventListener( + HTML5_MEDIA_EVENT.ENDED, + () => { + that.eventActionMapping[EVENT_TYPE.ENDED](MEDIA_TYPE.VIDEO); + }, + false + ); + } + + private playEventAction(mediaType) { + this._started = true; + this.recordEvent(mediaType, EVENT_TYPE.PLAY); + } + + private pauseEventAction(mediaType) { + this._started = false; + this.recordEvent(mediaType, EVENT_TYPE.PAUSE); + } + + private endedEventAction(mediaType) { + this._started = false; + this.recordEvent(mediaType, EVENT_TYPE.ENDED); + } + + private recordEvent(mediaType: string, eventType: string): void { + const newParams = Object.assign({}, this._params); + const { eventData } = newParams; + eventData.eventType = eventType; + if (mediaType === MEDIA_TYPE.VIDEO) { + eventData.properties.timestamp = this._mediaElement.currentTime; + eventData.properties.duration = this._mediaElement.duration; + } else { + eventData.properties.timestamp = this._financial( + this._iframePlayer.getCurrentTime() + ); + eventData.properties.duration = this._financial( + this._iframePlayer.getDuration() + ); + } + const percentage = + parseFloat(eventData.properties.timestamp) / + parseFloat(eventData.properties.duration); + eventData.properties.eventValue = Number(percentage.toFixed(4)); + delete eventData.properties.domElementId; + this._provider.putToBuffer(newParams); + } + + private _financial(x) { + return Number.parseFloat(x).toFixed(4); + } } diff --git a/packages/analytics/src/Providers/AmazonPersonalizeHelper/SessionInfoManager.ts b/packages/analytics/src/Providers/AmazonPersonalizeHelper/SessionInfoManager.ts index 678d2a48c61..b4f1649a0a2 100644 --- a/packages/analytics/src/Providers/AmazonPersonalizeHelper/SessionInfoManager.ts +++ b/packages/analytics/src/Providers/AmazonPersonalizeHelper/SessionInfoManager.ts @@ -10,113 +10,123 @@ * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ -import {RequestParams, SessionInfo} from './DataType'; -import {isEmpty, isEqual} from "lodash"; +import { RequestParams, SessionInfo } from './DataType'; +import { isEmpty, isEqual } from 'lodash'; import { v1 as uuid } from 'uuid'; import { StorageHelper, ConsoleLogger as Logger, JS } from '@aws-amplify/core'; import Cache from '@aws-amplify/cache'; -const PERSONALIZE_CACHE = "_awsct"; -const PERSONALIZE_CACHE_USERID = "_awsct_uid"; -const PERSONALIZE_CACHE_SESSIONID = "_awsct_sid"; -const DEFAULT_CACHE_PREFIX = "peronslize"; +const PERSONALIZE_CACHE = '_awsct'; +const PERSONALIZE_CACHE_USERID = '_awsct_uid'; +const PERSONALIZE_CACHE_SESSIONID = '_awsct_sid'; +const DEFAULT_CACHE_PREFIX = 'peronslize'; const TIMER_INTERVAL = 30 * 1000; -const DELIMITER = "."; +const DELIMITER = '.'; const CACHE_EXPIRY_IN_DAYS = 7; const logger = new Logger('AmazonPersonalizeProvider'); export class SessionInfoManager { - private _isBrowser; - private _cache; - private _timer; - private _timerKey; + private _isBrowser; + private _cache; + private _timer; + private _timerKey; - constructor(prefixKey="") { - this._isBrowser = JS.browserOrNode().isBrowser; - this._timerKey = uuid().substr(0,15); - this._refreshTimer(); - } + constructor(prefixKey = '') { + this._isBrowser = JS.browserOrNode().isBrowser; + this._timerKey = uuid().substr(0, 15); + this._refreshTimer(); + } - private _refreshTimer() { - if (this._timer) { - clearInterval(this._timer); - } - const that = this; - this._timer = setInterval( - () => { - that._timerKey = uuid().substr(0,15); - }, - TIMER_INTERVAL - ); - } + private _refreshTimer() { + if (this._timer) { + clearInterval(this._timer); + } + const that = this; + this._timer = setInterval(() => { + that._timerKey = uuid().substr(0, 15); + }, TIMER_INTERVAL); + } - private storeValue(key: string, value: any): void { - const today = new Date(); - const expire = new Date(); - expire.setTime(today.getTime() + 3600000 * 24 * CACHE_EXPIRY_IN_DAYS); - Cache.setItem(this._getCachePrefix(key), value, { expires: expire.getTime()}); - } + private storeValue(key: string, value: any): void { + const today = new Date(); + const expire = new Date(); + expire.setTime(today.getTime() + 3600000 * 24 * CACHE_EXPIRY_IN_DAYS); + Cache.setItem(this._getCachePrefix(key), value, { + expires: expire.getTime(), + }); + } - private retrieveValue(key: string): any { - return Cache.getItem(this._getCachePrefix(key)); - } + private retrieveValue(key: string): any { + return Cache.getItem(this._getCachePrefix(key)); + } - private _getCachePrefix(key): string { - if (this._isBrowser) { - return key + DELIMITER + window.location.host; - } - return DEFAULT_CACHE_PREFIX; - } + private _getCachePrefix(key): string { + if (this._isBrowser) { + return key + DELIMITER + window.location.host; + } + return DEFAULT_CACHE_PREFIX; + } - public getTimerKey() { - return this._timerKey; - } + public getTimerKey() { + return this._timerKey; + } - public updateSessionInfo(userId: string, sessionInfo: SessionInfo) { - const existUserId = sessionInfo.userId; - const existSessionId = sessionInfo.sessionId; - if (this._isRequireNewSession(userId, existUserId, existSessionId)) { - const newSessionId = uuid(); - this.storeValue(PERSONALIZE_CACHE_USERID, userId); - this.storeValue(PERSONALIZE_CACHE_SESSIONID, newSessionId); - sessionInfo.sessionId = newSessionId; - } else if (this._isRequireUpdateSessionInfo(userId, existUserId, existSessionId)){ - this.storeValue(PERSONALIZE_CACHE_USERID, userId); - } - sessionInfo.userId = userId; - } + public updateSessionInfo(userId: string, sessionInfo: SessionInfo) { + const existUserId = sessionInfo.userId; + const existSessionId = sessionInfo.sessionId; + if (this._isRequireNewSession(userId, existUserId, existSessionId)) { + const newSessionId = uuid(); + this.storeValue(PERSONALIZE_CACHE_USERID, userId); + this.storeValue(PERSONALIZE_CACHE_SESSIONID, newSessionId); + sessionInfo.sessionId = newSessionId; + } else if ( + this._isRequireUpdateSessionInfo(userId, existUserId, existSessionId) + ) { + this.storeValue(PERSONALIZE_CACHE_USERID, userId); + } + sessionInfo.userId = userId; + } - private _isRequireUpdateSessionInfo(userId: string, cachedSessionUserId: string, cachedSessionSessionId: string) : - boolean { - // anonymouse => sign in : hasSession && s_userId == null && curr_userId !=null - const isNoCachedSession : boolean = isEmpty(cachedSessionSessionId); - return !isNoCachedSession && isEmpty(cachedSessionUserId) && !isEmpty(userId); - } + private _isRequireUpdateSessionInfo( + userId: string, + cachedSessionUserId: string, + cachedSessionSessionId: string + ): boolean { + // anonymouse => sign in : hasSession && s_userId == null && curr_userId !=null + const isNoCachedSession: boolean = isEmpty(cachedSessionSessionId); + return ( + !isNoCachedSession && isEmpty(cachedSessionUserId) && !isEmpty(userId) + ); + } - public retrieveSessionInfo(trackingId: string): SessionInfo { - const sessionInfo = {}; - sessionInfo.trackingId = trackingId; - sessionInfo.sessionId = this.retrieveValue(PERSONALIZE_CACHE_SESSIONID); - sessionInfo.userId = this.retrieveValue(PERSONALIZE_CACHE_USERID); - if (isEmpty(sessionInfo.sessionId)) { - sessionInfo.sessionId = uuid(); - this.storeValue(PERSONALIZE_CACHE_SESSIONID, sessionInfo.sessionId); - } - this.storeValue(PERSONALIZE_CACHE,trackingId); - return sessionInfo; - } + public retrieveSessionInfo(trackingId: string): SessionInfo { + const sessionInfo = {}; + sessionInfo.trackingId = trackingId; + sessionInfo.sessionId = this.retrieveValue(PERSONALIZE_CACHE_SESSIONID); + sessionInfo.userId = this.retrieveValue(PERSONALIZE_CACHE_USERID); + if (isEmpty(sessionInfo.sessionId)) { + sessionInfo.sessionId = uuid(); + this.storeValue(PERSONALIZE_CACHE_SESSIONID, sessionInfo.sessionId); + } + this.storeValue(PERSONALIZE_CACHE, trackingId); + return sessionInfo; + } - private _isRequireNewSession( - userId: string, cachedSessionUserId: string, cachedSessionSessionId: string) : boolean { - // new session => 1. no cached session info 2. signOut: s_userId !=null && curr_userId ==null - // 3. switch account: s_userId !=null && curr_userId !=null && s_userId != curr_userId - const isNoCachedSession : boolean = isEmpty(cachedSessionSessionId); - const isSignoutCase : boolean = isEmpty(userId) && !isEmpty(cachedSessionUserId); - const isSwitchUserCase : boolean = !isEmpty(userId) && !isEmpty(cachedSessionUserId) - && !isEqual(userId, cachedSessionUserId); - return isNoCachedSession || isSignoutCase || isSwitchUserCase; - } + private _isRequireNewSession( + userId: string, + cachedSessionUserId: string, + cachedSessionSessionId: string + ): boolean { + // new session => 1. no cached session info 2. signOut: s_userId !=null && curr_userId ==null + // 3. switch account: s_userId !=null && curr_userId !=null && s_userId != curr_userId + const isNoCachedSession: boolean = isEmpty(cachedSessionSessionId); + const isSignoutCase: boolean = + isEmpty(userId) && !isEmpty(cachedSessionUserId); + const isSwitchUserCase: boolean = + !isEmpty(userId) && + !isEmpty(cachedSessionUserId) && + !isEqual(userId, cachedSessionUserId); + return isNoCachedSession || isSignoutCase || isSwitchUserCase; + } } - - diff --git a/packages/analytics/src/Providers/AmazonPersonalizeProvider.ts b/packages/analytics/src/Providers/AmazonPersonalizeProvider.ts index bd1dd981fc0..91f407b8d28 100644 --- a/packages/analytics/src/Providers/AmazonPersonalizeProvider.ts +++ b/packages/analytics/src/Providers/AmazonPersonalizeProvider.ts @@ -11,11 +11,17 @@ * and limitations under the License. */ -import { ConsoleLogger as Logger, Credentials, JS} from '@aws-amplify/core'; +import { ConsoleLogger as Logger, Credentials, JS } from '@aws-amplify/core'; import * as PersonalizeEvents from 'aws-sdk/clients/personalizeevents'; -import {SessionInfo, RequestParams, RecordEventPayload, SessionInfoManager, - RecordEventListPayload, MediaAutoTrack} from './AmazonPersonalizeHelper'; -import {isEmpty, isEqual, map, get} from "lodash"; +import { + SessionInfo, + RequestParams, + RecordEventPayload, + SessionInfoManager, + RecordEventListPayload, + MediaAutoTrack, +} from './AmazonPersonalizeHelper'; +import { isEmpty, isEqual, map, get } from 'lodash'; import { v1 as uuid } from 'uuid'; import { AnalyticsProvider } from '../types'; @@ -24,314 +30,366 @@ const logger = new Logger('AmazonPersonalizeProvider'); // events buffer const FLUSH_SIZE = 5; const FLUSH_SIZE_THRESHHOLD = 10; -const FLUSH_INTERVAL = 5*1000; // 5s +const FLUSH_INTERVAL = 5 * 1000; // 5s -const IDENTIFY_EVENT = "Identify"; +const IDENTIFY_EVENT = 'Identify'; export default class AmazonPersonalizeProvider implements AnalyticsProvider { + private _config; + private _personalize; + private _buffer; + private _timer; + private _sessionInfo: SessionInfo; + private _sessionManager; + private _listViewEventsCache; + private _isBrowser; - private _config; - private _personalize; - private _buffer; - private _timer; - private _sessionInfo: SessionInfo; - private _sessionManager; - private _listViewEventsCache; - private _isBrowser; + constructor(config?) { + this._buffer = []; + this._config = config ? config : {}; + this._config.flushSize = + this._config.flushSize > 0 && + this._config.flushSize <= FLUSH_SIZE_THRESHHOLD + ? this._config.flushSize + : FLUSH_SIZE; + this._config.flushInterval = this._config.flushInterval || FLUSH_INTERVAL; + this._sessionManager = new SessionInfoManager(); + if (!isEmpty(this._config.trackingId)) { + this._sessionInfo = this._sessionManager.retrieveSessionInfo( + this._config.trackingId + ); + } + this._isBrowser = JS.browserOrNode().isBrowser; - constructor(config?) { - this._buffer = []; - this._config = config? config : {}; - this._config.flushSize = this._config.flushSize > 0 - && this._config.flushSize <= FLUSH_SIZE_THRESHHOLD ? this._config.flushSize : FLUSH_SIZE; - this._config.flushInterval = this._config.flushInterval || FLUSH_INTERVAL; - this._sessionManager = new SessionInfoManager(); - if (!isEmpty(this._config.trackingId)) { - this._sessionInfo = this._sessionManager.retrieveSessionInfo(this._config.trackingId); - } - this._isBrowser = JS.browserOrNode().isBrowser; + // flush event buffer + this._setupTimer(); + } - // flush event buffer - this._setupTimer(); - } + private _setupTimer() { + if (this._timer) { + clearInterval(this._timer); + } + const { flushSize, flushInterval } = this._config; + const that = this; + this._timer = setInterval(() => { + that._sendFromBuffer(); + }, flushInterval); + } - private _setupTimer() { - if (this._timer) { - clearInterval(this._timer); - } - const { flushSize, flushInterval } = this._config; - const that = this; - this._timer = setInterval( - () => { - that._sendFromBuffer(); - }, - flushInterval - ); - } + /** + * Record event + * @param eventType - type of the event action. e.g. "Click" + * @param properties - properties of the event + * @return Promise + */ + public async record(params): Promise { + const credentials = await this._getCredentials(); + if (!credentials) return Promise.resolve(false); - /** - * Record event - * @param eventType - type of the event action. e.g. "Click" - * @param properties - properties of the event - * @return Promise - */ - public async record(params): Promise { - const credentials = await this._getCredentials(); - if (!credentials) return Promise.resolve(false); + Object.assign(params, { + config: this._config, + credentials, + sentAt: new Date().getTime() / 1000, + }); + const { eventType, properties } = params.event; - Object.assign(params, { config: this._config, credentials, sentAt: new Date().getTime() / 1000 }); - const { eventType, properties} = params.event; + if (eventType === IDENTIFY_EVENT) { + this._sessionManager.updateSessionInfo( + properties && properties.userId ? properties.userId : '', + this._sessionInfo + ); + return; + } else if (!isEmpty(params.event.userId)) { + this._sessionManager.updateSessionInfo( + params.event.userId, + this._sessionInfo + ); + } + const requestParams: RequestParams = this.generateRequestParams( + params, + this._sessionInfo + ); + if (eventType === 'MediaAutoTrack') { + if (this._isBrowser) { + if ( + !isEmpty( + get(requestParams, 'eventData.properties.domElementId', null) + ) + ) { + const isLoaded = await this.isElementFullyLoaded( + this.loadElement, + requestParams.eventData.properties['domElementId'], + 500, + 5 + ); + if (isLoaded) { + new MediaAutoTrack(requestParams, this); + } else { + logger.debug('Cannot find the media element.'); + } + } else { + logger.debug( + "Missing domElementId field in 'properties' for MediaAutoTrack event type." + ); + } + } else { + logger.debug('MediaAutoTrack only for browser'); + } + return; + } + return this.putToBuffer(requestParams); + } - if (eventType === IDENTIFY_EVENT) { - this._sessionManager.updateSessionInfo( - properties && properties.userId ? properties.userId : "", this._sessionInfo); - return; - } else if (!isEmpty(params.event.userId)) { - this._sessionManager.updateSessionInfo(params.event.userId, this._sessionInfo); - } - const requestParams: RequestParams = this.generateRequestParams(params, this._sessionInfo); - if (eventType === "MediaAutoTrack") { - if (this._isBrowser) { - if (!isEmpty(get(requestParams, "eventData.properties.domElementId", null))) { - const isLoaded = await this.isElementFullyLoaded( - this.loadElement, requestParams.eventData.properties["domElementId"], 500, 5); - if (isLoaded) { - new MediaAutoTrack(requestParams, this); - } else { - logger.debug("Cannot find the media element."); - } - } else { - logger.debug("Missing domElementId field in 'properties' for MediaAutoTrack event type."); - } - } else { - logger.debug("MediaAutoTrack only for browser"); - } - return; - } - return this.putToBuffer(requestParams); - } + private loadElement(domId): Promise { + return new Promise((resolve, reject) => { + if ( + document.getElementById(domId) && + document.getElementById(domId).clientHeight + ) { + return resolve(true); + } else { + return reject(true); + } + }); + } - private loadElement(domId): Promise { - return new Promise((resolve, reject) => { - if (document.getElementById(domId) && document.getElementById(domId).clientHeight) { - return resolve(true); - } else { - return reject(true); - } - }); - } + private isElementFullyLoaded( + operation, + params, + delay, + times + ): Promise { + const wait = ms => new Promise(r => setTimeout(r, ms)); + return new Promise((resolve, reject) => { + return operation(params) + .then(resolve) + .catch(reason => { + if (times - 1 > 0) { + return wait(delay) + .then( + this.isElementFullyLoaded.bind( + null, + operation, + params, + delay, + times - 1 + ) + ) + .then(resolve) + .catch(reject); + } + return reject(reason); + }); + }); + } - private isElementFullyLoaded(operation, params, delay, times): Promise { - const wait = ms => new Promise(r => setTimeout(r, ms)); - return new Promise((resolve, reject) => { - return operation(params) - .then(resolve) - .catch((reason) => { - if (times - 1 > 0) { - return wait(delay) - .then(this.isElementFullyLoaded.bind(null, operation, params, delay, times - 1)) - .then(resolve) - .catch(reject); - } - return reject(reason); - }); - }); - } + /** + * get the category of the plugin + */ + public getCategory(): string { + return 'Analytics'; + } - /** - * get the category of the plugin - */ - public getCategory(): string { - return 'Analytics'; - } + /** + * get provider name of the plugin + */ + public getProviderName(): string { + return 'AmazonPersonalize'; + } - /** - * get provider name of the plugin - */ - public getProviderName(): string { - return 'AmazonPersonalize'; - } + /** + * configure the plugin + * @param {Object} config - configuration + */ + public configure(config): object { + logger.debug('configure Analytics', config); + const conf = config ? config : {}; + this._config = Object.assign({}, this._config, conf); + if (!isEmpty(this._config.trackingId)) { + this._sessionInfo = this._sessionManager.retrieveSessionInfo( + this._config.trackingId + ); + } + this._setupTimer(); + return this._config; + } - /** - * configure the plugin - * @param {Object} config - configuration - */ - public configure(config): object { - logger.debug('configure Analytics', config); - const conf = config? config : {}; - this._config = Object.assign({}, this._config, conf); - if (!isEmpty(this._config.trackingId)) { - this._sessionInfo = this._sessionManager.retrieveSessionInfo(this._config.trackingId); - } - this._setupTimer(); - return this._config; - } + /** + * Generate the requestParams from customer input params and sessionInfo + * @private + * @param eventData - customer input for event data + * @param api - api name + * @return RequestParams - wrapper object with all information required for make request + */ + private generateRequestParams(params, sessionInfo): RequestParams { + const requestParams = {}; + const { eventType, properties } = params.event; + requestParams.eventData = { eventType: eventType, properties: properties }; + requestParams.sessionInfo = sessionInfo; + requestParams.sentAt = params.sentAt; + requestParams.credentials = params.credentials; + requestParams.config = params.config; + return requestParams; + } - /** - * Generate the requestParams from customer input params and sessionInfo - * @private - * @param eventData - customer input for event data - * @param api - api name - * @return RequestParams - wrapper object with all information required for make request - */ - private generateRequestParams(params, sessionInfo): RequestParams { - const requestParams = {}; - const {eventType, properties} = params.event; - requestParams.eventData = {"eventType": eventType, "properties": properties}; - requestParams.sessionInfo = sessionInfo; - requestParams.sentAt = params.sentAt; - requestParams.credentials = params.credentials; - requestParams.config = params.config; - return requestParams; - } + /** + * record an event + * @param {Object} params - the params of an event + */ + private _sendEvents(group) { + const groupLen = group.length; + if (groupLen === 0) { + logger.debug('events array is empty, directly return'); + return; + } - /** - * record an event - * @param {Object} params - the params of an event - */ - private _sendEvents(group) { - const groupLen = group.length; - if (groupLen === 0) { - logger.debug('events array is empty, directly return'); - return; - } + const { config, credentials, sessionInfo } = group[0]; - const { config, credentials, sessionInfo } = group[0]; + const initClients = this._init(config, credentials); + if (!initClients) return false; + if (groupLen > 0) { + const events: RecordEventPayload[] = []; + for (let i = 0; i < groupLen; i += 1) { + const params: RequestParams = group.shift(); + const eventPayload: RecordEventPayload = this._generateSingleRecordPayload( + params, + sessionInfo + ); + events.push(eventPayload); + } + const payload = {}; + payload.trackingId = sessionInfo.trackingId; + payload.sessionId = sessionInfo.sessionId; + payload.userId = sessionInfo.userId; + payload.eventList = events; + this._personalize.putEvents(payload, (err, data) => { + if (err) logger.debug('Failed to call putEvents in Personalize', err); + else logger.debug('Put events'); + }); + } + } - const initClients = this._init(config, credentials); - if (!initClients) return false; - if (groupLen > 0) { - const events: RecordEventPayload[] = []; - for (let i = 0; i < groupLen; i += 1) { - const params: RequestParams = group.shift(); - const eventPayload: RecordEventPayload = this._generateSingleRecordPayload(params, sessionInfo); - events.push(eventPayload); - } - const payload = {}; - payload.trackingId = sessionInfo.trackingId; - payload.sessionId = sessionInfo.sessionId; - payload.userId = sessionInfo.userId; - payload.eventList = events; - this._personalize.putEvents(payload, (err, data) => { - if (err) logger.debug('Failed to call putEvents in Personalize', err); - else logger.debug('Put events'); - }); - } - } + /** + * Put event into buffer + * @private + * @param params - params for the event recording + */ + private putToBuffer(params: RequestParams) { + if (this._buffer.length < this._config.flushSize) { + this._buffer.push(params); + } else { + this._buffer.push(params); + this._sendFromBuffer(); + } + return Promise.resolve(true); + } - /** - * Put event into buffer - * @private - * @param params - params for the event recording - */ - private putToBuffer(params: RequestParams) { - if (this._buffer.length < this._config.flushSize) { - this._buffer.push(params); - } else { - this._buffer.push(params); - this._sendFromBuffer(); - } - return Promise.resolve(true); - } + /** + * flush the buffer and batch sending the request + * @private + * @param eventsParams - the buffer for cache the payload + */ + private _sendFromBuffer() { + const size = this._buffer.length; + if (size <= 0) return; + const eventsGroups = []; + let preCred = null; + let group = []; + for (let i = 0; i < size; i += 1) { + const currRequestParams: RequestParams = this._buffer.shift(); + const cred = currRequestParams.credentials; + const sessionInfo = currRequestParams.sessionInfo; + if (i === 0) { + group.push(currRequestParams); + preCred = cred; + } else { + if ( + isEqual(sessionInfo, this._sessionInfo) && + cred.sessionToken === preCred.sessionToken && + cred.identityId === preCred.identityId + ) { + logger.debug('no change for cred, put event in the same group'); + group.push(currRequestParams); + } else { + eventsGroups.push(group); + group = []; + group.push(currRequestParams); + preCred = cred; + this._sessionInfo = sessionInfo; + } + } + } + eventsGroups.push(group); - /** - * flush the buffer and batch sending the request - * @private - * @param eventsParams - the buffer for cache the payload - */ - private _sendFromBuffer() { - const size = this._buffer.length; - if (size <= 0) return; - const eventsGroups = []; - let preCred = null; - let group = []; - for (let i = 0; i < size; i += 1) { - const currRequestParams: RequestParams = this._buffer.shift(); - const cred = currRequestParams.credentials; - const sessionInfo = currRequestParams.sessionInfo; - if (i === 0) { - group.push(currRequestParams); - preCred = cred; - } else { - if (isEqual(sessionInfo, this._sessionInfo) - && cred.sessionToken === preCred.sessionToken - && cred.identityId === preCred.identityId) { - logger.debug('no change for cred, put event in the same group'); - group.push(currRequestParams); - } else { - eventsGroups.push(group); - group = []; - group.push(currRequestParams); - preCred = cred; - this._sessionInfo = sessionInfo; - } - } - } - eventsGroups.push(group); + eventsGroups.map(group => { + this._sendEvents(group); + }); + } - eventsGroups.map(group => { - this._sendEvents(group); - }); - } + /** + * Generate the record payload for single event + * @private + * @param params - RequestParams + */ + private _generateSingleRecordPayload( + params: RequestParams, + sessionInfo + ): RecordEventPayload { + const { eventData, sentAt } = params; + const trackPayload = {}; + trackPayload.sentAt = sentAt; + trackPayload.properties = eventData.properties; + trackPayload.eventId = + this._sessionManager.getTimerKey() + sessionInfo.sessionId; + trackPayload.eventType = eventData.eventType; + return trackPayload; + } - /** - * Generate the record payload for single event - * @private - * @param params - RequestParams - */ - private _generateSingleRecordPayload(params: RequestParams, sessionInfo): RecordEventPayload { - const { eventData, sentAt } = params; - const trackPayload = {}; - trackPayload.sentAt = sentAt; - trackPayload.properties = eventData.properties; - trackPayload.eventId = this._sessionManager.getTimerKey() + sessionInfo.sessionId; - trackPayload.eventType = eventData.eventType; - return trackPayload; - } + /** + * Initialize the personalize client + * @private + * @param params - RequestParams + */ + private _init(config, credentials) { + logger.debug('init clients'); - /** - * Initialize the personalize client - * @private - * @param params - RequestParams - */ - private _init(config, credentials) { - logger.debug('init clients'); + if ( + this._personalize && + this._config.credentials && + this._config.credentials.sessionToken === credentials.sessionToken && + this._config.credentials.identityId === credentials.identityId + ) { + logger.debug('no change for analytics config, directly return from init'); + return true; + } - if (this._personalize - && this._config.credentials - && this._config.credentials.sessionToken === credentials.sessionToken - && this._config.credentials.identityId === credentials.identityId) { - logger.debug('no change for analytics config, directly return from init'); - return true; - } + this._config.credentials = credentials; + const { region } = config; + logger.debug('initialize personalize with credentials', credentials); + this._personalize = new PersonalizeEvents({ + apiVersion: '2018-03-22', + region, + credentials, + }); - this._config.credentials = credentials; - const { region } = config; - logger.debug('initialize personalize with credentials', credentials); - this._personalize = new PersonalizeEvents({ - apiVersion: '2018-03-22', - region, - credentials - }); + return true; + } - return true; - } - - /** - * check if current credentials exists - * @private - */ - private _getCredentials() { - const that = this; - return Credentials.get() - .then(credentials => { - if (!credentials) return null; - logger.debug('set credentials for analytics', that._config.credentials); - return Credentials.shear(credentials); - }) - .catch(err => { - logger.debug('ensure credentials error', err); - return null; - }); - } + /** + * check if current credentials exists + * @private + */ + private _getCredentials() { + const that = this; + return Credentials.get() + .then(credentials => { + if (!credentials) return null; + logger.debug('set credentials for analytics', that._config.credentials); + return Credentials.shear(credentials); + }) + .catch(err => { + logger.debug('ensure credentials error', err); + return null; + }); + } } diff --git a/packages/analytics/src/index.ts b/packages/analytics/src/index.ts index 27b1f9448aa..503bddb14d3 100644 --- a/packages/analytics/src/index.ts +++ b/packages/analytics/src/index.ts @@ -15,10 +15,10 @@ import AnalyticsClass from './Analytics'; import { AnalyticsProvider } from './types'; import Amplify, { - ConsoleLogger as Logger, - Hub, - Linking, - Platform + ConsoleLogger as Logger, + Hub, + Linking, + Platform, } from '@aws-amplify/core'; const logger = new Logger('Analytics'); @@ -29,8 +29,8 @@ let analyticsConfigured = false; let _instance: AnalyticsClass = null; if (!_instance) { - logger.debug('Create Analytics Instance'); - _instance = new AnalyticsClass(); + logger.debug('Create Analytics Instance'); + _instance = new AnalyticsClass(); } const Analytics = _instance; @@ -41,108 +41,115 @@ export { AnalyticsProvider }; export { AnalyticsClass }; export * from './Providers'; -const listener = (capsule) => { - const { channel, payload, source } = capsule; - logger.debug('on hub capsule ' + channel, payload); - - switch(channel) { - case 'auth': - authEvent(payload); - break; - case 'storage': - storageEvent(payload); - break; - case 'analytics': - analyticsEvent(payload); - break; - default: - break; - } +const listener = capsule => { + const { channel, payload, source } = capsule; + logger.debug('on hub capsule ' + channel, payload); + + switch (channel) { + case 'auth': + authEvent(payload); + break; + case 'storage': + storageEvent(payload); + break; + case 'analytics': + analyticsEvent(payload); + break; + default: + break; + } }; -const storageEvent = (payload) => { - const { data: { attrs, metrics }} = payload; - if (!attrs) return; - - if (analyticsConfigured) { - Analytics.record({ - name: 'Storage', - attributes: attrs, - metrics - }).catch(e => { - logger.debug('Failed to send the storage event automatically', e); - }); - } +const storageEvent = payload => { + const { + data: { attrs, metrics }, + } = payload; + if (!attrs) return; + + if (analyticsConfigured) { + Analytics.record({ + name: 'Storage', + attributes: attrs, + metrics, + }).catch(e => { + logger.debug('Failed to send the storage event automatically', e); + }); + } }; -const authEvent = (payload) => { - const { event } = payload; - if (!event) { return; } - - switch(event) { - case 'signIn': - if (authConfigured && analyticsConfigured) { - Analytics.record({ - name: '_userauth.sign_in' - }).catch(e => { - logger.debug('Failed to send the sign in event automatically', e); - }); - } - break; - case 'signUp': - if (authConfigured && analyticsConfigured) { - Analytics.record({ - name: '_userauth.sign_up' - }).catch(e => { - logger.debug('Failed to send the sign up event automatically', e); - }); - } - break; - case 'signOut': - break; - case 'signIn_failure': - if (authConfigured && analyticsConfigured) { - Analytics.record({ - name: '_userauth.auth_fail' - }).catch(e => { - logger.debug('Failed to send the sign in failure event automatically', e); - }); - } - break; - case 'configured': - authConfigured = true; - if (authConfigured && analyticsConfigured) { - sendEvents(); - } - break; - } +const authEvent = payload => { + const { event } = payload; + if (!event) { + return; + } + + switch (event) { + case 'signIn': + if (authConfigured && analyticsConfigured) { + Analytics.record({ + name: '_userauth.sign_in', + }).catch(e => { + logger.debug('Failed to send the sign in event automatically', e); + }); + } + break; + case 'signUp': + if (authConfigured && analyticsConfigured) { + Analytics.record({ + name: '_userauth.sign_up', + }).catch(e => { + logger.debug('Failed to send the sign up event automatically', e); + }); + } + break; + case 'signOut': + break; + case 'signIn_failure': + if (authConfigured && analyticsConfigured) { + Analytics.record({ + name: '_userauth.auth_fail', + }).catch(e => { + logger.debug( + 'Failed to send the sign in failure event automatically', + e + ); + }); + } + break; + case 'configured': + authConfigured = true; + if (authConfigured && analyticsConfigured) { + sendEvents(); + } + break; + } }; -const analyticsEvent = (payload) => { - const { event } = payload; - if (!event) return; - - switch(event) { - case 'pinpointProvider_configured': - analyticsConfigured = true; - if (authConfigured && analyticsConfigured) { - sendEvents(); - } - break; - } +const analyticsEvent = payload => { + const { event } = payload; + if (!event) return; + + switch (event) { + case 'pinpointProvider_configured': + analyticsConfigured = true; + if (authConfigured && analyticsConfigured) { + sendEvents(); + } + break; + } }; const sendEvents = () => { - const config = Analytics.configure(); - if (!endpointUpdated && config['autoSessionRecord']) { - Analytics.updateEndpoint({ immediate: true }).catch(e => { - logger.debug('Failed to update the endpoint', e); - }); - endpointUpdated = true; - } - Analytics.autoTrack('session', { - enable: config['autoSessionRecord'] - }); + const config = Analytics.configure(); + if (!endpointUpdated && config['autoSessionRecord']) { + Analytics.updateEndpoint({ immediate: true }).catch(e => { + logger.debug('Failed to update the endpoint', e); + }); + endpointUpdated = true; + } + Analytics.autoTrack('session', { + enable: config['autoSessionRecord'], + }); }; Hub.listen('auth', listener); diff --git a/packages/analytics/src/setupTests.ts b/packages/analytics/src/setupTests.ts index 516fdbde8bf..a983ce42264 100644 --- a/packages/analytics/src/setupTests.ts +++ b/packages/analytics/src/setupTests.ts @@ -1,4 +1,4 @@ -const anyGlobal = (global as any); +const anyGlobal = global as any; -anyGlobal.navigator = anyGlobal.navigator || {}; +anyGlobal.navigator = anyGlobal.navigator || {}; anyGlobal.navigator.sendBeacon = anyGlobal.navigator.sendBeacon || jest.fn(); diff --git a/packages/analytics/src/trackers/EventTracker.ts b/packages/analytics/src/trackers/EventTracker.ts index f8c147d078d..459710c75b2 100644 --- a/packages/analytics/src/trackers/EventTracker.ts +++ b/packages/analytics/src/trackers/EventTracker.ts @@ -18,103 +18,108 @@ import { ConsoleLogger as Logger, JS } from '@aws-amplify/core'; const logger = new Logger('EventTracker'); const defaultOpts: EventTrackOpts = { - enable: false, - events: ['click'], - selectorPrefix: 'data-amplify-analytics-', - provider: 'AWSPinpoint' + enable: false, + events: ['click'], + selectorPrefix: 'data-amplify-analytics-', + provider: 'AWSPinpoint', }; export default class EventTracker { - private _tracker; - private _config: EventTrackOpts; - private _delegates; - - constructor(tracker, opts) { - if (!JS.browserOrNode().isBrowser || !window.addEventListener) { - logger.debug('not in the supported web environment'); - return; - } - - this._config = Object.assign({}, defaultOpts, opts); - this._tracker = tracker; - this._delegates = {}; - this._trackFunc = this._trackFunc.bind(this); - - logger.debug('initialize pageview tracker with opts', this._config); - - this.configure(this._config); - } - - configure(opts?: EventTrackOpts) { - Object.assign(this._config, opts); - - if (!this._config.enable) { - Object.keys(this._delegates).forEach(key => { - if (typeof this._delegates[key].destroy === 'function') - this._delegates[key].destroy(); - }); - this._delegates = {}; - } else if (this._config.enable && Object.keys(this._delegates).length === 0) { - const selector = '[' + this._config.selectorPrefix + 'on]'; - this._config.events.forEach((evt) => { - this._delegates[evt] = delegate( - document, - evt, - selector, - this._trackFunc, - {composed: true, useCapture: true} - ); - }); - } - - return this._config; - } - - private async _trackFunc(event, element) { - // the events specifed in 'amplify-analytics-on' selector - const customAttrs = {}; - const events = element - .getAttribute(this._config.selectorPrefix + 'on') - .split(/\s*,\s*/); - const eventName = element.getAttribute(this._config.selectorPrefix + 'name'); - - const attrs = element.getAttribute(this._config.selectorPrefix + 'attrs'); - if (attrs) { - attrs.split(/\s*,\s*/) - .forEach(attr => { - const tmp = attr.trim().split(/\s*:\s*/); - customAttrs[tmp[0]] = tmp[1]; - }); - } - - const defaultAttrs = typeof this._config.attributes === 'function'? - await this._config.attributes() : this._config.attributes; - - const attributes = Object.assign( - { - type: event.type, - target: `${event.target.localName} with id ${event.target.id}` - }, - defaultAttrs, - customAttrs - ); - - logger.debug('events needed to be recorded', events); - logger.debug('attributes needed to be attached', customAttrs); - if (events.indexOf(event.type) < 0) { - logger.debug(`event ${event.type} is not selected to be recorded`); - return; - } - - this._tracker( - { - name: eventName || 'event', - attributes - }, - this._config.provider - ).catch(e => { - logger.debug(`Failed to record the ${event.type} event', ${e}`); - }); - } - + private _tracker; + private _config: EventTrackOpts; + private _delegates; + + constructor(tracker, opts) { + if (!JS.browserOrNode().isBrowser || !window.addEventListener) { + logger.debug('not in the supported web environment'); + return; + } + + this._config = Object.assign({}, defaultOpts, opts); + this._tracker = tracker; + this._delegates = {}; + this._trackFunc = this._trackFunc.bind(this); + + logger.debug('initialize pageview tracker with opts', this._config); + + this.configure(this._config); + } + + configure(opts?: EventTrackOpts) { + Object.assign(this._config, opts); + + if (!this._config.enable) { + Object.keys(this._delegates).forEach(key => { + if (typeof this._delegates[key].destroy === 'function') + this._delegates[key].destroy(); + }); + this._delegates = {}; + } else if ( + this._config.enable && + Object.keys(this._delegates).length === 0 + ) { + const selector = '[' + this._config.selectorPrefix + 'on]'; + this._config.events.forEach(evt => { + this._delegates[evt] = delegate( + document, + evt, + selector, + this._trackFunc, + { composed: true, useCapture: true } + ); + }); + } + + return this._config; + } + + private async _trackFunc(event, element) { + // the events specifed in 'amplify-analytics-on' selector + const customAttrs = {}; + const events = element + .getAttribute(this._config.selectorPrefix + 'on') + .split(/\s*,\s*/); + const eventName = element.getAttribute( + this._config.selectorPrefix + 'name' + ); + + const attrs = element.getAttribute(this._config.selectorPrefix + 'attrs'); + if (attrs) { + attrs.split(/\s*,\s*/).forEach(attr => { + const tmp = attr.trim().split(/\s*:\s*/); + customAttrs[tmp[0]] = tmp[1]; + }); + } + + const defaultAttrs = + typeof this._config.attributes === 'function' + ? await this._config.attributes() + : this._config.attributes; + + const attributes = Object.assign( + { + type: event.type, + target: `${event.target.localName} with id ${event.target.id}`, + }, + defaultAttrs, + customAttrs + ); + + logger.debug('events needed to be recorded', events); + logger.debug('attributes needed to be attached', customAttrs); + if (events.indexOf(event.type) < 0) { + logger.debug(`event ${event.type} is not selected to be recorded`); + return; + } + + this._tracker( + { + name: eventName || 'event', + attributes, + }, + this._config.provider + ).catch(e => { + logger.debug(`Failed to record the ${event.type} event', ${e}`); + }); + } } diff --git a/packages/analytics/src/trackers/PageViewTracker.ts b/packages/analytics/src/trackers/PageViewTracker.ts index fe24c2310d4..6bb5f05f5b4 100644 --- a/packages/analytics/src/trackers/PageViewTracker.ts +++ b/packages/analytics/src/trackers/PageViewTracker.ts @@ -19,136 +19,149 @@ const logger = new Logger('PageViewTracker'); const PREV_URL_KEY = 'aws-amplify-analytics-prevUrl'; const getUrl = () => { - if (!JS.browserOrNode().isBrowser) return ''; - else return window.location.origin + window.location.pathname; + if (!JS.browserOrNode().isBrowser) return ''; + else return window.location.origin + window.location.pathname; }; const defaultOpts: pageViewTrackOpts = { - enable: false, - provider: 'AWSPinpoint', - getUrl + enable: false, + provider: 'AWSPinpoint', + getUrl, }; - - export default class PageViewTracker { - private _config: pageViewTrackOpts; - private _tracker; - private _hasEnabled; - - constructor(tracker, opts) { - logger.debug('initialize pageview tracker with opts', opts); - this._config = Object.assign({}, defaultOpts, opts); - this._tracker = tracker; - this._hasEnabled = false; - this._trackFunc = this._trackFunc.bind(this); - - if (this._config.type === 'SPA') { - this._pageViewTrackSPA(); - } else { - this._pageViewTrackDefault(); - } - } - - public configure(opts?: pageViewTrackOpts) { - Object.assign(this._config, opts); - - // if spa, need to remove those listeners if disabled - if (this._config.type === 'SPA') { - this._pageViewTrackSPA(); - } - - return this._config; - } - - private _isSameUrl() { - const prevUrl = sessionStorage.getItem(PREV_URL_KEY); - const curUrl = this._config.getUrl(); - - if (prevUrl === curUrl){ - logger.debug('the url is same'); - return true; - } - else return false; - } - - private async _pageViewTrackDefault() { - if (!JS.browserOrNode().isBrowser || !window.addEventListener || !window.sessionStorage) { - logger.debug('not in the supported web enviroment'); - return; - } - const url = this._config.getUrl(); - const customAttrs = typeof this._config.attributes === 'function'? - await this._config.attributes() : this._config.attributes; - const attributes = Object.assign( - { - url - }, - customAttrs - ); - - if (this._config.enable && !this._isSameUrl()) { - this._tracker( - { - name: this._config.eventName || 'pageView', - attributes - }, - this._config.provider - ).catch(e => { - logger.debug('Failed to record the page view event', e); - }); - sessionStorage.setItem(PREV_URL_KEY, url); - } - } - - private async _trackFunc() { - if (!JS.browserOrNode().isBrowser || !window.addEventListener || !history.pushState || !window.sessionStorage) { - logger.debug('not in the supported web enviroment'); - return; - } - - const url = this._config.getUrl(); - const customAttrs = typeof this._config.attributes === 'function'? - await this._config.attributes() : this._config.attributes; - const attributes = Object.assign( - { - url - }, - customAttrs - ); - - if (!this._isSameUrl()){ - this._tracker( - { - name: this._config.eventName || 'pageView', - attributes - }, - this._config.provider - ).catch(e => { - logger.debug('Failed to record the page view event', e); - }); - sessionStorage.setItem(PREV_URL_KEY, url); - } - } - - - private _pageViewTrackSPA() { - if (!JS.browserOrNode().isBrowser || !window.addEventListener || !history.pushState) { - logger.debug('not in the supported web enviroment'); - return; - } - - if (this._config.enable && !this._hasEnabled) { - MethodEmbed.add(history, 'pushState', this._trackFunc); - MethodEmbed.add(history, 'replaceState', this._trackFunc); - window.addEventListener('popstate', this._trackFunc); - this._trackFunc(); - this._hasEnabled = true; - } else { - MethodEmbed.remove(history, 'pushState'); - MethodEmbed.remove(history, 'replaceState'); - window.removeEventListener('popstate', this._trackFunc); - this._hasEnabled = false; - } - } + private _config: pageViewTrackOpts; + private _tracker; + private _hasEnabled; + + constructor(tracker, opts) { + logger.debug('initialize pageview tracker with opts', opts); + this._config = Object.assign({}, defaultOpts, opts); + this._tracker = tracker; + this._hasEnabled = false; + this._trackFunc = this._trackFunc.bind(this); + + if (this._config.type === 'SPA') { + this._pageViewTrackSPA(); + } else { + this._pageViewTrackDefault(); + } + } + + public configure(opts?: pageViewTrackOpts) { + Object.assign(this._config, opts); + + // if spa, need to remove those listeners if disabled + if (this._config.type === 'SPA') { + this._pageViewTrackSPA(); + } + + return this._config; + } + + private _isSameUrl() { + const prevUrl = sessionStorage.getItem(PREV_URL_KEY); + const curUrl = this._config.getUrl(); + + if (prevUrl === curUrl) { + logger.debug('the url is same'); + return true; + } else return false; + } + + private async _pageViewTrackDefault() { + if ( + !JS.browserOrNode().isBrowser || + !window.addEventListener || + !window.sessionStorage + ) { + logger.debug('not in the supported web enviroment'); + return; + } + const url = this._config.getUrl(); + const customAttrs = + typeof this._config.attributes === 'function' + ? await this._config.attributes() + : this._config.attributes; + const attributes = Object.assign( + { + url, + }, + customAttrs + ); + + if (this._config.enable && !this._isSameUrl()) { + this._tracker( + { + name: this._config.eventName || 'pageView', + attributes, + }, + this._config.provider + ).catch(e => { + logger.debug('Failed to record the page view event', e); + }); + sessionStorage.setItem(PREV_URL_KEY, url); + } + } + + private async _trackFunc() { + if ( + !JS.browserOrNode().isBrowser || + !window.addEventListener || + !history.pushState || + !window.sessionStorage + ) { + logger.debug('not in the supported web enviroment'); + return; + } + + const url = this._config.getUrl(); + const customAttrs = + typeof this._config.attributes === 'function' + ? await this._config.attributes() + : this._config.attributes; + const attributes = Object.assign( + { + url, + }, + customAttrs + ); + + if (!this._isSameUrl()) { + this._tracker( + { + name: this._config.eventName || 'pageView', + attributes, + }, + this._config.provider + ).catch(e => { + logger.debug('Failed to record the page view event', e); + }); + sessionStorage.setItem(PREV_URL_KEY, url); + } + } + + private _pageViewTrackSPA() { + if ( + !JS.browserOrNode().isBrowser || + !window.addEventListener || + !history.pushState + ) { + logger.debug('not in the supported web enviroment'); + return; + } + + if (this._config.enable && !this._hasEnabled) { + MethodEmbed.add(history, 'pushState', this._trackFunc); + MethodEmbed.add(history, 'replaceState', this._trackFunc); + window.addEventListener('popstate', this._trackFunc); + this._trackFunc(); + this._hasEnabled = true; + } else { + MethodEmbed.remove(history, 'pushState'); + MethodEmbed.remove(history, 'replaceState'); + window.removeEventListener('popstate', this._trackFunc); + this._hasEnabled = false; + } + } } diff --git a/packages/analytics/src/trackers/SessionTracker-rn.ts b/packages/analytics/src/trackers/SessionTracker-rn.ts index d68e42f0ef3..d946fd6a563 100644 --- a/packages/analytics/src/trackers/SessionTracker-rn.ts +++ b/packages/analytics/src/trackers/SessionTracker-rn.ts @@ -11,126 +11,132 @@ * and limitations under the License. */ - // the session tracker for react native +// the session tracker for react native import { ConsoleLogger as Logger } from '@aws-amplify/core'; import { SessionTrackOpts } from '../types'; -import { AppState } from 'react-native'; +import { AppState } from 'react-native'; const logger = new Logger('SessionTracker'); const defaultOpts: SessionTrackOpts = { - enable: false, - provider: 'AWSPinpoint' + enable: false, + provider: 'AWSPinpoint', }; let initialEventSent = false; export default class SessionTracker { - private _tracker; - private _hasEnabled; - private _config: SessionTrackOpts; - private _currentState; - - constructor(tracker, opts) { - this._config = Object.assign({}, defaultOpts, opts); - this._tracker = tracker; - - this._hasEnabled = false; - this._trackFunc = this._trackFunc.bind(this); - this._currentState = AppState.currentState; - this.configure(this._config); - } - - private _envCheck() { - if (!AppState) { - logger.debug('not in the supported react native environment'); - return false; - } - return true; - } - - private async _trackFunc(nextAppState) { - const customAttrs = typeof this._config.attributes === 'function'? - await this._config.attributes() : this._config.attributes; - const attributes = Object.assign( - {}, - customAttrs - ); - - if (this._currentState.match(/inactive|background/) && nextAppState === 'active') { - logger.debug('App has come to the foreground, recording start session'); - this._tracker( - { - name: '_session.start', - attributes - }, - this._config.provider - ).catch(e => { - logger.debug('record session start event failed.', e); - }); - } - if (this._currentState.match(/active/) && nextAppState.match(/inactive|background/)) { - logger.debug('App has come to inactive/background, recording stop session'); - this._tracker( - { - name: '_session.stop', - attributes, - immediate: true - }, - this._config.provider - ).catch(e => { - logger.debug('record session stop event failed.', e); - }); - } - - this._currentState = nextAppState; - } - - // to keep configure a synchronized function - private async _sendInitialEvent() { - if (initialEventSent) { - logger.debug('the start session has been sent when the page is loaded'); - return; - } else { - initialEventSent = true; - } - - const customAttrs = typeof this._config.attributes === 'function'? - await this._config.attributes() : this._config.attributes; - const attributes = Object.assign( - {}, - customAttrs - ); - - this._tracker( - { - name: '_session.start', - attributes - }, - this._config.provider - ).catch(e => { - logger.debug('record session start event failed.', e); - }); - } - - configure(opts?: SessionTrackOpts) { - if (!this._envCheck()) { - return this._config; - } - - Object.assign(this._config, opts); - if (this._config.enable && !this._hasEnabled) { - // send a start session as soon as it's enabled - this._sendInitialEvent(); - // listen on events - AppState.addEventListener('change', this._trackFunc, false); - this._hasEnabled = true; - } else if (!this._config.enable && this._hasEnabled) { - AppState.removeEventListener('change', this._trackFunc, false); - this._hasEnabled = false; - } - - return this._config; - } + private _tracker; + private _hasEnabled; + private _config: SessionTrackOpts; + private _currentState; + + constructor(tracker, opts) { + this._config = Object.assign({}, defaultOpts, opts); + this._tracker = tracker; + + this._hasEnabled = false; + this._trackFunc = this._trackFunc.bind(this); + this._currentState = AppState.currentState; + this.configure(this._config); + } + + private _envCheck() { + if (!AppState) { + logger.debug('not in the supported react native environment'); + return false; + } + return true; + } + + private async _trackFunc(nextAppState) { + const customAttrs = + typeof this._config.attributes === 'function' + ? await this._config.attributes() + : this._config.attributes; + const attributes = Object.assign({}, customAttrs); + + if ( + this._currentState.match(/inactive|background/) && + nextAppState === 'active' + ) { + logger.debug('App has come to the foreground, recording start session'); + this._tracker( + { + name: '_session.start', + attributes, + }, + this._config.provider + ).catch(e => { + logger.debug('record session start event failed.', e); + }); + } + if ( + this._currentState.match(/active/) && + nextAppState.match(/inactive|background/) + ) { + logger.debug( + 'App has come to inactive/background, recording stop session' + ); + this._tracker( + { + name: '_session.stop', + attributes, + immediate: true, + }, + this._config.provider + ).catch(e => { + logger.debug('record session stop event failed.', e); + }); + } + + this._currentState = nextAppState; + } + + // to keep configure a synchronized function + private async _sendInitialEvent() { + if (initialEventSent) { + logger.debug('the start session has been sent when the page is loaded'); + return; + } else { + initialEventSent = true; + } + + const customAttrs = + typeof this._config.attributes === 'function' + ? await this._config.attributes() + : this._config.attributes; + const attributes = Object.assign({}, customAttrs); + + this._tracker( + { + name: '_session.start', + attributes, + }, + this._config.provider + ).catch(e => { + logger.debug('record session start event failed.', e); + }); + } + + configure(opts?: SessionTrackOpts) { + if (!this._envCheck()) { + return this._config; + } + + Object.assign(this._config, opts); + if (this._config.enable && !this._hasEnabled) { + // send a start session as soon as it's enabled + this._sendInitialEvent(); + // listen on events + AppState.addEventListener('change', this._trackFunc, false); + this._hasEnabled = true; + } else if (!this._config.enable && this._hasEnabled) { + AppState.removeEventListener('change', this._trackFunc, false); + this._hasEnabled = false; + } + + return this._config; + } } diff --git a/packages/analytics/src/trackers/SessionTracker.ts b/packages/analytics/src/trackers/SessionTracker.ts index ce592eadc19..ea2ca158896 100644 --- a/packages/analytics/src/trackers/SessionTracker.ts +++ b/packages/analytics/src/trackers/SessionTracker.ts @@ -19,162 +19,166 @@ import { SessionTrackOpts } from '../types'; const logger = new Logger('SessionTracker'); const defaultOpts: SessionTrackOpts = { - enable: false, - provider: 'AWSPinpoint' + enable: false, + provider: 'AWSPinpoint', }; let initialEventSent = false; export default class SessionTracker { - private _tracker; - private _hasEnabled; - private _config: SessionTrackOpts; - - private _hidden; - private _visibilityChange; - - constructor(tracker, opts) { - this._config = Object.assign({}, defaultOpts, opts); - this._tracker = tracker; - - this._hasEnabled = false; - this._trackFunc = this._trackFunc.bind(this); - this._trackBeforeUnload = this._trackBeforeUnload.bind(this); - - this.configure(this._config); - } - - private _envCheck() { - if (!JS.browserOrNode().isBrowser) { - return false; - } - - if (!document || !document.addEventListener) { - logger.debug('not in the supported web environment'); - return false; - } - - if (typeof document.hidden !== 'undefined') { - this._hidden = 'hidden'; - this._visibilityChange = 'visibilitychange'; - } else if (typeof document['msHidden'] !== 'undefined') { - this._hidden = 'msHidden'; - this._visibilityChange = 'msvisibilitychange'; - } else if (typeof document['webkitHidden'] !== 'undefined') { - this._hidden = 'webkitHidden'; - this._visibilityChange = 'webkitvisibilitychange'; - } else { - logger.debug('not in the supported web environment'); - return false; - } - return true; - } - - private async _trackFunc() { - const customAttrs = typeof this._config.attributes === 'function' ? - await this._config.attributes() : this._config.attributes; - - const attributes = Object.assign( - {}, - customAttrs - ); - - if (document.visibilityState === this._hidden) { - this._tracker( - { - name: '_session.stop', - attributes - }, - this._config.provider - ).catch(e => { - logger.debug('record session stop event failed.', e); - }); - } else { - this._tracker( - { - name: '_session.start', - attributes - }, - this._config.provider - ).catch(e => { - logger.debug('record session start event failed.', e); - }); - } - } - - private _trackBeforeUnload(event) { - // before unload callback cannot be async => https://github.com/aws-amplify/amplify-js/issues/2088 - - const customAttrs = typeof this._config.attributes === 'function' ? - Promise.resolve(this._config.attributes()) : Promise.resolve(this._config.attributes); - - customAttrs.then(custom => { - const attributes = Object.assign( - {}, - custom - ); - - this._tracker( - { - name: '_session.stop', - attributes, - immediate: true - }, - this._config.provider - ).catch(e => { - logger.debug('record session stop event failed.', e); - }); - }); - } - - // to keep configure a synchronized function - private async _sendInitialEvent() { - if (initialEventSent) { - logger.debug('the start session has been sent when the page is loaded'); - return; - } else { - initialEventSent = true; - } - - const customAttrs = typeof this._config.attributes === 'function' - ? await this._config.attributes() - : this._config.attributes; - - const attributes = Object.assign( - {}, - customAttrs - ); - - this._tracker( - { - name: '_session.start', - attributes - }, - this._config.provider - ).catch(e => { - logger.debug('record session start event failed.', e); - }); - } - - configure(opts?: SessionTrackOpts) { - if (!this._envCheck()) { - return this._config; - } - - Object.assign(this._config, opts); - if (this._config.enable && !this._hasEnabled) { - // send a start session as soon as it's enabled - this._sendInitialEvent(); - // listen on events - document.addEventListener(this._visibilityChange, this._trackFunc, false); - window.addEventListener("beforeunload", this._trackBeforeUnload, false); - this._hasEnabled = true; - } else if (!this._config.enable && this._hasEnabled) { - document.removeEventListener(this._visibilityChange, this._trackFunc, false); - window.removeEventListener("beforeunload", this._trackBeforeUnload, false); - this._hasEnabled = false; - } - - return this._config; - } + private _tracker; + private _hasEnabled; + private _config: SessionTrackOpts; + + private _hidden; + private _visibilityChange; + + constructor(tracker, opts) { + this._config = Object.assign({}, defaultOpts, opts); + this._tracker = tracker; + + this._hasEnabled = false; + this._trackFunc = this._trackFunc.bind(this); + this._trackBeforeUnload = this._trackBeforeUnload.bind(this); + + this.configure(this._config); + } + + private _envCheck() { + if (!JS.browserOrNode().isBrowser) { + return false; + } + + if (!document || !document.addEventListener) { + logger.debug('not in the supported web environment'); + return false; + } + + if (typeof document.hidden !== 'undefined') { + this._hidden = 'hidden'; + this._visibilityChange = 'visibilitychange'; + } else if (typeof document['msHidden'] !== 'undefined') { + this._hidden = 'msHidden'; + this._visibilityChange = 'msvisibilitychange'; + } else if (typeof document['webkitHidden'] !== 'undefined') { + this._hidden = 'webkitHidden'; + this._visibilityChange = 'webkitvisibilitychange'; + } else { + logger.debug('not in the supported web environment'); + return false; + } + return true; + } + + private async _trackFunc() { + const customAttrs = + typeof this._config.attributes === 'function' + ? await this._config.attributes() + : this._config.attributes; + + const attributes = Object.assign({}, customAttrs); + + if (document.visibilityState === this._hidden) { + this._tracker( + { + name: '_session.stop', + attributes, + }, + this._config.provider + ).catch(e => { + logger.debug('record session stop event failed.', e); + }); + } else { + this._tracker( + { + name: '_session.start', + attributes, + }, + this._config.provider + ).catch(e => { + logger.debug('record session start event failed.', e); + }); + } + } + + private _trackBeforeUnload(event) { + // before unload callback cannot be async => https://github.com/aws-amplify/amplify-js/issues/2088 + + const customAttrs = + typeof this._config.attributes === 'function' + ? Promise.resolve(this._config.attributes()) + : Promise.resolve(this._config.attributes); + + customAttrs.then(custom => { + const attributes = Object.assign({}, custom); + + this._tracker( + { + name: '_session.stop', + attributes, + immediate: true, + }, + this._config.provider + ).catch(e => { + logger.debug('record session stop event failed.', e); + }); + }); + } + + // to keep configure a synchronized function + private async _sendInitialEvent() { + if (initialEventSent) { + logger.debug('the start session has been sent when the page is loaded'); + return; + } else { + initialEventSent = true; + } + + const customAttrs = + typeof this._config.attributes === 'function' + ? await this._config.attributes() + : this._config.attributes; + + const attributes = Object.assign({}, customAttrs); + + this._tracker( + { + name: '_session.start', + attributes, + }, + this._config.provider + ).catch(e => { + logger.debug('record session start event failed.', e); + }); + } + + configure(opts?: SessionTrackOpts) { + if (!this._envCheck()) { + return this._config; + } + + Object.assign(this._config, opts); + if (this._config.enable && !this._hasEnabled) { + // send a start session as soon as it's enabled + this._sendInitialEvent(); + // listen on events + document.addEventListener(this._visibilityChange, this._trackFunc, false); + window.addEventListener('beforeunload', this._trackBeforeUnload, false); + this._hasEnabled = true; + } else if (!this._config.enable && this._hasEnabled) { + document.removeEventListener( + this._visibilityChange, + this._trackFunc, + false + ); + window.removeEventListener( + 'beforeunload', + this._trackBeforeUnload, + false + ); + this._hasEnabled = false; + } + + return this._config; + } } diff --git a/packages/analytics/src/trackers/reactnative.ts b/packages/analytics/src/trackers/reactnative.ts index a3bb238ba9c..99a91a06f62 100644 --- a/packages/analytics/src/trackers/reactnative.ts +++ b/packages/analytics/src/trackers/reactnative.ts @@ -1,11 +1,11 @@ import SessionTracker from './SessionTracker-rn'; class EventTracker { - constructor(tracker, opts) {} + constructor(tracker, opts) {} } class PageViewTracker { - constructor(tracker, opts) {} + constructor(tracker, opts) {} } export { EventTracker, PageViewTracker, SessionTracker }; diff --git a/packages/analytics/src/types/Analytics.ts b/packages/analytics/src/types/Analytics.ts index bacae23a1cc..09928d12e96 100644 --- a/packages/analytics/src/types/Analytics.ts +++ b/packages/analytics/src/types/Analytics.ts @@ -12,43 +12,49 @@ */ import { AWS } from '@aws-amplify/core'; /** -* Analytics instance options -*/ + * Analytics instance options + */ export interface AnalyticsOptions { - appId: string; - platform?: string; - clientId?: string; - region?: string; - credentials?: AWS.Credentials & AWS.CognitoIdentityCredentials; + appId: string; + platform?: string; + clientId?: string; + region?: string; + credentials?: AWS.Credentials & AWS.CognitoIdentityCredentials; } export interface EventAttributes { - [key: string]: string; + [key: string]: string; } export interface EventMetrics { - [key: string]: number; + [key: string]: number; } export interface pageViewTrackOpts { - enable: boolean, - type?: string - eventName?: string, - provider?: string, - attributes?: EventAttributes | (()=> EventAttributes | Promise), - getUrl?: (() => string) + enable: boolean; + type?: string; + eventName?: string; + provider?: string; + attributes?: + | EventAttributes + | (() => EventAttributes | Promise); + getUrl?: () => string; } export interface EventTrackOpts { - enable: boolean, - events?: Array, - selectorPrefix?: string, - provider?: string, - attributes?: EventAttributes | (()=> EventAttributes | Promise) + enable: boolean; + events?: Array; + selectorPrefix?: string; + provider?: string; + attributes?: + | EventAttributes + | (() => EventAttributes | Promise); } export interface SessionTrackOpts { - enable: boolean, - attributes?: EventAttributes | (()=> EventAttributes | Promise), - provider?: string, + enable: boolean; + attributes?: + | EventAttributes + | (() => EventAttributes | Promise); + provider?: string; } diff --git a/packages/analytics/src/types/Provider.ts b/packages/analytics/src/types/Provider.ts index fa934583e84..a4ea9473ae0 100644 --- a/packages/analytics/src/types/Provider.ts +++ b/packages/analytics/src/types/Provider.ts @@ -12,22 +12,22 @@ */ export interface PromiseHandlers { - resolve: Function, - reject: Function -} + resolve: Function; + reject: Function; +} export interface AnalyticsProvider { - // you need to implement those methods + // you need to implement those methods + + // configure your provider + configure(config: object): object; - // configure your provider - configure(config: object): object; + // record events and returns true if succeeds + record(params: object, handlers?: PromiseHandlers): Promise; - // record events and returns true if succeeds - record(params: object, handlers?: PromiseHandlers): Promise; + // return 'Analytics'; + getCategory(): string; - // return 'Analytics'; - getCategory(): string; - - // return the name of you provider - getProviderName(): string; + // return the name of you provider + getProviderName(): string; } diff --git a/packages/analytics/src/utils/MethodEmbed.ts b/packages/analytics/src/utils/MethodEmbed.ts index 6d9b7e2ee7b..ae61593adc6 100644 --- a/packages/analytics/src/utils/MethodEmbed.ts +++ b/packages/analytics/src/utils/MethodEmbed.ts @@ -11,48 +11,49 @@ * and limitations under the License. */ -const lists : MethodEmbed[] = []; +const lists: MethodEmbed[] = []; export default class MethodEmbed { - public context; - public methodName; - private _originalMethod; - private _bindedMethod; - - static add(context, methodName, methodOverride) { - getInstance(context, methodName).set(methodOverride); - } - - static remove(context, methodName) { - getInstance(context, methodName).remove(); - } - - constructor(context, methodName) { - this.context = context; - this.methodName = methodName; - - this._originalMethod = context[methodName].bind(context); - } - - public set(methodOverride) { - this.context[this.methodName] = (...args) => { - return methodOverride(this._originalMethod(...args)); - }; - } - - public remove() { - this.context[this.methodName] = this._originalMethod; - } + public context; + public methodName; + private _originalMethod; + private _bindedMethod; + + static add(context, methodName, methodOverride) { + getInstance(context, methodName).set(methodOverride); + } + + static remove(context, methodName) { + getInstance(context, methodName).remove(); + } + + constructor(context, methodName) { + this.context = context; + this.methodName = methodName; + + this._originalMethod = context[methodName].bind(context); + } + + public set(methodOverride) { + this.context[this.methodName] = (...args) => { + return methodOverride(this._originalMethod(...args)); + }; + } + + public remove() { + this.context[this.methodName] = this._originalMethod; + } } function getInstance(context, methodName): MethodEmbed { - let instance = lists - .filter((h) => h.context === context && h.methodName === methodName)[0]; + let instance = lists.filter( + h => h.context === context && h.methodName === methodName + )[0]; - if (!instance) { - instance = new MethodEmbed(context, methodName); - lists.push(instance); - } + if (!instance) { + instance = new MethodEmbed(context, methodName); + lists.push(instance); + } - return instance; + return instance; } diff --git a/packages/analytics/src/vendor/dom-utils/closest.ts b/packages/analytics/src/vendor/dom-utils/closest.ts index 3e3136a00f2..d8c081425bf 100644 --- a/packages/analytics/src/vendor/dom-utils/closest.ts +++ b/packages/analytics/src/vendor/dom-utils/closest.ts @@ -14,11 +14,12 @@ import parents from './parents'; * @return {Element|undefined} The matching element or undefined. */ export default function closest(element, selector, shouldCheckSelf = false) { - if (!(element && element.nodeType === 1 && selector)) return; - const parentElements = - (shouldCheckSelf ? [element] : []).concat(parents(element)); + if (!(element && element.nodeType === 1 && selector)) return; + const parentElements = (shouldCheckSelf ? [element] : []).concat( + parents(element) + ); - for (let i = 0, parent; parent = parentElements[i]; i++) { - if (matches(parent, selector)) return parent; - } + for (let i = 0, parent; (parent = parentElements[i]); i++) { + if (matches(parent, selector)) return parent; + } } diff --git a/packages/analytics/src/vendor/dom-utils/delegate.ts b/packages/analytics/src/vendor/dom-utils/delegate.ts index 69207f62409..7d6c07f4da1 100644 --- a/packages/analytics/src/vendor/dom-utils/delegate.ts +++ b/packages/analytics/src/vendor/dom-utils/delegate.ts @@ -18,35 +18,40 @@ import matches from './matches'; * @return {Object} The delegate object. It contains a destroy method. */ export default function delegate( - ancestor, eventType, selector, callback, opts = {}) { - // Defines the event listener. - const listener = function(event) { - let delegateTarget; + ancestor, + eventType, + selector, + callback, + opts = {} +) { + // Defines the event listener. + const listener = function(event) { + let delegateTarget; - // If opts.composed is true and the event originated from inside a Shadow - // tree, check the composed path nodes. - if (opts['composed'] && typeof event['composedPath'] === 'function') { - const composedPath = event.composedPath(); - for (let i = 0, node; node = composedPath[i]; i++) { - if (node.nodeType === 1 && matches(node, selector)) { - delegateTarget = node; - } - } - } else { - // Otherwise check the parents. - delegateTarget = closest(event.target, selector, true); - } + // If opts.composed is true and the event originated from inside a Shadow + // tree, check the composed path nodes. + if (opts['composed'] && typeof event['composedPath'] === 'function') { + const composedPath = event.composedPath(); + for (let i = 0, node; (node = composedPath[i]); i++) { + if (node.nodeType === 1 && matches(node, selector)) { + delegateTarget = node; + } + } + } else { + // Otherwise check the parents. + delegateTarget = closest(event.target, selector, true); + } - if (delegateTarget) { - callback.call(delegateTarget, event, delegateTarget); - } - }; + if (delegateTarget) { + callback.call(delegateTarget, event, delegateTarget); + } + }; - ancestor.addEventListener(eventType, listener, opts['useCapture']); + ancestor.addEventListener(eventType, listener, opts['useCapture']); - return { - destroy: () => { - ancestor.removeEventListener(eventType, listener, opts['useCapture']); - }, - }; + return { + destroy: () => { + ancestor.removeEventListener(eventType, listener, opts['useCapture']); + }, + }; } diff --git a/packages/analytics/src/vendor/dom-utils/dispatch.ts b/packages/analytics/src/vendor/dom-utils/dispatch.ts index d658537044b..730b357263d 100644 --- a/packages/analytics/src/vendor/dom-utils/dispatch.ts +++ b/packages/analytics/src/vendor/dom-utils/dispatch.ts @@ -16,36 +16,44 @@ * be false if any of the event listeners called `preventDefault`. */ export default function dispatch( - element, eventType, evtName = 'Event', init_dict = {}) { - let event; - let isCustom; - let initDict = init_dict; - let eventName = evtName; - - // eventName is optional - if (typeof eventName === 'object') { - initDict = eventName; - eventName = 'Event'; - } + element, + eventType, + evtName = 'Event', + init_dict = {} +) { + let event; + let isCustom; + let initDict = init_dict; + let eventName = evtName; - initDict['bubbles'] = initDict['bubbles'] || false; - initDict['cancelable'] = initDict['cancelable'] || false; - initDict['composed'] = initDict['composed'] || false; + // eventName is optional + if (typeof eventName === 'object') { + initDict = eventName; + eventName = 'Event'; + } - // If a detail property is passed, this is a custom event. - if ('detail' in initDict) isCustom = true; - eventName = isCustom ? 'CustomEvent' : eventName; + initDict['bubbles'] = initDict['bubbles'] || false; + initDict['cancelable'] = initDict['cancelable'] || false; + initDict['composed'] = initDict['composed'] || false; - // Tries to create the event using constructors, if that doesn't work, - // fallback to `document.createEvent()`. - try { - event = new window[eventName](eventType, initDict); - } catch(err) { - event = document.createEvent(eventName); - const initMethod = 'init' + (isCustom ? 'Custom' : '') + 'Event'; - event[initMethod](eventType, initDict['bubbles'], - initDict['cancelable'], initDict['detail']); - } + // If a detail property is passed, this is a custom event. + if ('detail' in initDict) isCustom = true; + eventName = isCustom ? 'CustomEvent' : eventName; - return element.dispatchEvent(event); + // Tries to create the event using constructors, if that doesn't work, + // fallback to `document.createEvent()`. + try { + event = new window[eventName](eventType, initDict); + } catch (err) { + event = document.createEvent(eventName); + const initMethod = 'init' + (isCustom ? 'Custom' : '') + 'Event'; + event[initMethod]( + eventType, + initDict['bubbles'], + initDict['cancelable'], + initDict['detail'] + ); + } + + return element.dispatchEvent(event); } diff --git a/packages/analytics/src/vendor/dom-utils/get-attributes.ts b/packages/analytics/src/vendor/dom-utils/get-attributes.ts index 14592f8e1dc..3fb46d2eb68 100644 --- a/packages/analytics/src/vendor/dom-utils/get-attributes.ts +++ b/packages/analytics/src/vendor/dom-utils/get-attributes.ts @@ -10,17 +10,17 @@ * object is returned. */ export default function getAttributes(element) { - const attrs = {}; + const attrs = {}; - // Validate input. - if (!(element && element.nodeType === 1)) return attrs; + // Validate input. + if (!(element && element.nodeType === 1)) return attrs; - // Return an empty object if there are no attributes. - const map = element.attributes; - if (map.length === 0) return {}; + // Return an empty object if there are no attributes. + const map = element.attributes; + if (map.length === 0) return {}; - for (let i = 0, attr; attr = map[i]; i++) { - attrs[attr.name] = attr.value; - } - return attrs; + for (let i = 0, attr; (attr = map[i]); i++) { + attrs[attr.name] = attr.value; + } + return attrs; } diff --git a/packages/analytics/src/vendor/dom-utils/matches.ts b/packages/analytics/src/vendor/dom-utils/matches.ts index 924feb952c2..083140567d8 100644 --- a/packages/analytics/src/vendor/dom-utils/matches.ts +++ b/packages/analytics/src/vendor/dom-utils/matches.ts @@ -4,14 +4,18 @@ import { JS } from '@aws-amplify/core'; -const proto = JS.browserOrNode().isBrowser && window['Element']? window['Element'].prototype: null; -const nativeMatches = proto ? proto.matches || - proto.matchesSelector || - proto.webkitMatchesSelector || - proto.mozMatchesSelector || - proto.msMatchesSelector || - proto.oMatchesSelector : null; - +const proto = + JS.browserOrNode().isBrowser && window['Element'] + ? window['Element'].prototype + : null; +const nativeMatches = proto + ? proto.matches || + proto.matchesSelector || + proto.webkitMatchesSelector || + proto.mozMatchesSelector || + proto.msMatchesSelector || + proto.oMatchesSelector + : null; /** * Tests if a DOM elements matches any of the test DOM elements or selectors. @@ -21,25 +25,25 @@ const nativeMatches = proto ? proto.matches || * @return {boolean} True of any part of the test matches. */ export default function matches(element, test) { - // Validate input. - if (element && element.nodeType === 1 && test) { - // if test is a string or DOM element test it. - if (typeof test === 'string' || test.nodeType === 1) { - return element === test || - matchesSelector(element, /** @type {string} */ (test)); - } else if ('length' in test) { - // if it has a length property iterate over the items - // and return true if any match. - for (let i = 0, item; item = test[i]; i++) { - if (element === item || matchesSelector(element, item)) return true; - } - } - } - // Still here? Return false - return false; + // Validate input. + if (element && element.nodeType === 1 && test) { + // if test is a string or DOM element test it. + if (typeof test === 'string' || test.nodeType === 1) { + return ( + element === test || matchesSelector(element, /** @type {string} */ test) + ); + } else if ('length' in test) { + // if it has a length property iterate over the items + // and return true if any match. + for (let i = 0, item; (item = test[i]); i++) { + if (element === item || matchesSelector(element, item)) return true; + } + } + } + // Still here? Return false + return false; } - /** * Tests whether a DOM element matches a selector. This polyfills the native * Element.prototype.matches method across browsers. @@ -48,11 +52,11 @@ export default function matches(element, test) { * @return {boolean} True if the selector matches. */ function matchesSelector(element, selector) { - if (typeof selector !== 'string') return false; - if (nativeMatches) return nativeMatches.call(element, selector); - const nodes = element.parentNode.querySelectorAll(selector); - for (let i = 0, node; node = nodes[i]; i++) { - if (node === element) return true; - } - return false; + if (typeof selector !== 'string') return false; + if (nativeMatches) return nativeMatches.call(element, selector); + const nodes = element.parentNode.querySelectorAll(selector); + for (let i = 0, node; (node = nodes[i]); i++) { + if (node === element) return true; + } + return false; } diff --git a/packages/analytics/src/vendor/dom-utils/parents.ts b/packages/analytics/src/vendor/dom-utils/parents.ts index 479f0f7a151..cba6eda68d8 100644 --- a/packages/analytics/src/vendor/dom-utils/parents.ts +++ b/packages/analytics/src/vendor/dom-utils/parents.ts @@ -9,11 +9,11 @@ * parent elements are found. */ export default function parents(ele) { - const list = []; - let element = ele; - while (element && element.parentNode && element.parentNode.nodeType === 1) { - element = /** @type {!Element} */ (element.parentNode); - list.push(element); - } - return list; + const list = []; + let element = ele; + while (element && element.parentNode && element.parentNode.nodeType === 1) { + element = /** @type {!Element} */ element.parentNode; + list.push(element); + } + return list; } diff --git a/packages/analytics/src/vendor/dom-utils/parse-url.ts b/packages/analytics/src/vendor/dom-utils/parse-url.ts index 65e54230205..561881bcec9 100644 --- a/packages/analytics/src/vendor/dom-utils/parse-url.ts +++ b/packages/analytics/src/vendor/dom-utils/parse-url.ts @@ -17,50 +17,50 @@ const cache = {}; * @return {!Object} An object with the same properties as a `Location`. */ export default function parseUrl(u) { - let url = u; - // All falsy values (as well as ".") should map to the current URL. - url = (!url || url === '.') ? location.href : url; + let url = u; + // All falsy values (as well as ".") should map to the current URL. + url = !url || url === '.' ? location.href : url; - if (cache[url]) return cache[url]; + if (cache[url]) return cache[url]; - a.href = url; + a.href = url; - // When parsing file relative paths (e.g. `../index.html`), IE will correctly - // resolve the `href` property but will keep the `..` in the `path` property. - // It will also not include the `host` or `hostname` properties. Furthermore, - // IE will sometimes return no protocol or just a colon, especially for things - // like relative protocol URLs (e.g. "//google.com"). - // To workaround all of these issues, we reparse with the full URL from the - // `href` property. - if (url.charAt(0) === '.' || url.charAt(0) === '/') return parseUrl(a.href); + // When parsing file relative paths (e.g. `../index.html`), IE will correctly + // resolve the `href` property but will keep the `..` in the `path` property. + // It will also not include the `host` or `hostname` properties. Furthermore, + // IE will sometimes return no protocol or just a colon, especially for things + // like relative protocol URLs (e.g. "//google.com"). + // To workaround all of these issues, we reparse with the full URL from the + // `href` property. + if (url.charAt(0) === '.' || url.charAt(0) === '/') return parseUrl(a.href); - // Don't include default ports. - let port = (a.port === HTTP_PORT || a.port === HTTPS_PORT) ? '' : a.port; + // Don't include default ports. + let port = a.port === HTTP_PORT || a.port === HTTPS_PORT ? '' : a.port; - // PhantomJS sets the port to "0" when using the file: protocol. - port = port === '0' ? '' : port; + // PhantomJS sets the port to "0" when using the file: protocol. + port = port === '0' ? '' : port; - // Sometimes IE incorrectly includes a port for default ports - // (e.g. `:80` or `:443`) even when no port is specified in the URL. - // http://bit.ly/1rQNoMg - const host = a.host.replace(DEFAULT_PORT, ''); + // Sometimes IE incorrectly includes a port for default ports + // (e.g. `:80` or `:443`) even when no port is specified in the URL. + // http://bit.ly/1rQNoMg + const host = a.host.replace(DEFAULT_PORT, ''); - // Not all browser support `origin` so we have to build it. - const origin = a['origin'] ? a['origin'] : a.protocol + '//' + host; + // Not all browser support `origin` so we have to build it. + const origin = a['origin'] ? a['origin'] : a.protocol + '//' + host; - // Sometimes IE doesn't include the leading slash for pathname. - // http://bit.ly/1rQNoMg - const pathname = a.pathname.charAt(0) === '/' ? a.pathname : '/' + a.pathname; + // Sometimes IE doesn't include the leading slash for pathname. + // http://bit.ly/1rQNoMg + const pathname = a.pathname.charAt(0) === '/' ? a.pathname : '/' + a.pathname; - return cache[url] = { - hash: a.hash, - host, - hostname: a.hostname, - href: a.href, - origin, - pathname, - port, - protocol: a.protocol, - search: a.search, - }; + return (cache[url] = { + hash: a.hash, + host, + hostname: a.hostname, + href: a.href, + origin, + pathname, + port, + protocol: a.protocol, + search: a.search, + }); } diff --git a/packages/analytics/tslint.json b/packages/analytics/tslint.json index 9d5f01d0502..1bb9e144d24 100644 --- a/packages/analytics/tslint.json +++ b/packages/analytics/tslint.json @@ -1,72 +1,45 @@ - { - "defaultSeverity": "error", - "plugins": [ - "prettier" - ], - "extends": [ - //"tslint-config-airbnb" - ], - "jsRules": {}, - "rules": { - "prefer-const": true, - "max-line-length": [true, 120], - "no-empty-interface": true, - "no-var-keyword": true, - "object-literal-shorthand": true, - "no-eval": true, - "space-before-function-paren": [ - true, - { - "anonymous": "never", - "named": "never" - } - ], - "no-parameter-reassignment": true, - "align": [ - true, - "arguments", - "parameters" - ], - "no-duplicate-imports": true, - "one-variable-per-declaration": [ - false, - "ignore-for-loop" - ], - "triple-equals": [ - true, - "allow-null-check" - ], - "no-boolean-literal-compare": true, - "comment-format": [ - true, - "check-space" - ], - "indent": [ - true, - "space", - 2 - ], - "whitespace": [ - false, - "check-branch", - "check-decl", - "check-operator", - "check-preblock" - ], - "eofline": true, - "variable-name": [ - true, - "check-format", // 22.2 - "allow-pascal-case", - "allow-snake-case", - "allow-leading-underscore" - ], - "semicolon": [ - true, - "always", - "ignore-interfaces" - ] - }, - "rulesDirectory": [] -} \ No newline at end of file + "defaultSeverity": "error", + "plugins": ["prettier"], + "extends": [], + "jsRules": {}, + "rules": { + "prefer-const": true, + "max-line-length": [true, 120], + "no-empty-interface": true, + "no-var-keyword": true, + "object-literal-shorthand": true, + "no-eval": true, + "space-before-function-paren": [ + true, + { + "anonymous": "never", + "named": "never" + } + ], + "no-parameter-reassignment": true, + "align": [true, "parameters"], + "no-duplicate-imports": true, + "one-variable-per-declaration": [false, "ignore-for-loop"], + "triple-equals": [true, "allow-null-check"], + "comment-format": [true, "check-space"], + "indent": [false], + "whitespace": [ + false, + "check-branch", + "check-decl", + "check-operator", + "check-preblock" + ], + "eofline": true, + "variable-name": [ + true, + "check-format", + "allow-pascal-case", + "allow-snake-case", + "allow-leading-underscore" + ], + "semicolon": [true, "always", "ignore-interfaces"] + }, + "rulesDirectory": [] +} diff --git a/packages/analytics/webpack.config.js b/packages/analytics/webpack.config.js index f18d9dffe00..6e8f745213a 100644 --- a/packages/analytics/webpack.config.js +++ b/packages/analytics/webpack.config.js @@ -1,56 +1,57 @@ const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); -const CompressionPlugin = require("compression-webpack-plugin") +const CompressionPlugin = require('compression-webpack-plugin'); module.exports = { - entry: { - 'aws-amplify-analytics': './src/index.ts', - 'aws-amplify-analytics.min': './src/index.ts' - }, - output: { - filename: '[name].js', - path: __dirname + '/dist', - library: 'aws_amplify_analytics', - libraryTarget: 'umd', - umdNamedDefine: true, - devtoolModuleFilenameTemplate: require('../aws-amplify/webpack-utils').devtoolModuleFilenameTemplate - }, - // Enable sourcemaps for debugging webpack's output. - devtool: 'source-map', - resolve: { - // Add '.ts' and '.tsx' as resolvable extensions. - extensions: ['.ts', '.tsx', '.js', '.json'] - }, - plugins: [ - new UglifyJsPlugin({ - minimize: true, - sourceMap: true, - include: /\.min\.js$/, - }), - new CompressionPlugin({ - include: /\.min\.js$/, - }) - ], - module: { - rules: [ - // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'. - { - test: /\.tsx?$/, - loader: 'awesome-typescript-loader', - exclude: /node_modules/, - query: { - declaration: false - } - }, - // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. - //{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' }, - { - test: /\.jsx?$/, - exclude: /node_modules/, - loader: 'babel-loader', - query: { - presets: ['react', 'es2015', 'stage-2'], - } - } - ] - } + entry: { + 'aws-amplify-analytics': './src/index.ts', + 'aws-amplify-analytics.min': './src/index.ts', + }, + output: { + filename: '[name].js', + path: __dirname + '/dist', + library: 'aws_amplify_analytics', + libraryTarget: 'umd', + umdNamedDefine: true, + devtoolModuleFilenameTemplate: require('../aws-amplify/webpack-utils') + .devtoolModuleFilenameTemplate, + }, + // Enable sourcemaps for debugging webpack's output. + devtool: 'source-map', + resolve: { + // Add '.ts' and '.tsx' as resolvable extensions. + extensions: ['.ts', '.tsx', '.js', '.json'], + }, + plugins: [ + new UglifyJsPlugin({ + minimize: true, + sourceMap: true, + include: /\.min\.js$/, + }), + new CompressionPlugin({ + include: /\.min\.js$/, + }), + ], + module: { + rules: [ + // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'. + { + test: /\.tsx?$/, + loader: 'awesome-typescript-loader', + exclude: /node_modules/, + query: { + declaration: false, + }, + }, + // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. + //{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' }, + { + test: /\.jsx?$/, + exclude: /node_modules/, + loader: 'babel-loader', + query: { + presets: ['react', 'es2015', 'stage-2'], + }, + }, + ], + }, }; diff --git a/packages/api/CHANGELOG.md b/packages/api/CHANGELOG.md index 758f929a49a..d366e15ff56 100644 --- a/packages/api/CHANGELOG.md +++ b/packages/api/CHANGELOG.md @@ -7,1691 +7,1251 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package @aws-amplify/api - - - - ## [1.1.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.1.0...@aws-amplify/api@1.1.1) (2019-09-05) **Note:** Version bump only for package @aws-amplify/api - - - - # [1.1.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.42...@aws-amplify/api@1.1.0) (2019-09-04) - ### Features -* **@aws-amplify/api:** Add ability to set withCredentials in API ([#3634](https://github.com/aws/aws-amplify/issues/3634)) ([8437578](https://github.com/aws/aws-amplify/commit/8437578)) - - - - +- **@aws-amplify/api:** Add ability to set withCredentials in API ([#3634](https://github.com/aws/aws-amplify/issues/3634)) ([8437578](https://github.com/aws/aws-amplify/commit/8437578)) ## [1.0.42](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.41...@aws-amplify/api@1.0.42) (2019-08-05) **Note:** Version bump only for package @aws-amplify/api - - - - ## [1.0.41](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.40...@aws-amplify/api@1.0.41) (2019-07-31) **Note:** Version bump only for package @aws-amplify/api - - - - ## [1.0.40](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.39...@aws-amplify/api@1.0.40) (2019-07-30) **Note:** Version bump only for package @aws-amplify/api - - - - ## [1.0.39](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.37...@aws-amplify/api@1.0.39) (2019-07-18) **Note:** Version bump only for package @aws-amplify/api - - - - -## [1.0.38-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.38-unstable.1...@aws-amplify/api@1.0.38-unstable.2) (2019-07-12) - - +## [1.0.38-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.38-unstable.1...@aws-amplify/api@1.0.38-unstable.2) (2019-07-12) **Note:** Version bump only for package @aws-amplify/api -## [1.0.38-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.38-unstable.0...@aws-amplify/api@1.0.38-unstable.1) (2019-07-12) - - +## [1.0.38-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.38-unstable.0...@aws-amplify/api@1.0.38-unstable.1) (2019-07-12) **Note:** Version bump only for package @aws-amplify/api -## [1.0.38-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.37...@aws-amplify/api@1.0.38-unstable.0) (2019-07-10) - - +## [1.0.38-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.37...@aws-amplify/api@1.0.38-unstable.0) (2019-07-10) **Note:** Version bump only for package @aws-amplify/api -## [1.0.37](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.37-unstable.0...@aws-amplify/api@1.0.37) (2019-07-09) - - +## [1.0.37](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.37-unstable.0...@aws-amplify/api@1.0.37) (2019-07-09) **Note:** Version bump only for package @aws-amplify/api -## [1.0.37-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.36...@aws-amplify/api@1.0.37-unstable.0) (2019-06-27) - - +## [1.0.37-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.36...@aws-amplify/api@1.0.37-unstable.0) (2019-06-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.36](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.36-unstable.3...@aws-amplify/api@1.0.36) (2019-06-17) - - +## [1.0.36](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.36-unstable.3...@aws-amplify/api@1.0.36) (2019-06-17) **Note:** Version bump only for package @aws-amplify/api -## [1.0.36-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.36-unstable.2...@aws-amplify/api@1.0.36-unstable.3) (2019-06-14) - - +## [1.0.36-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.36-unstable.2...@aws-amplify/api@1.0.36-unstable.3) (2019-06-14) **Note:** Version bump only for package @aws-amplify/api -## [1.0.36-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.36-unstable.1...@aws-amplify/api@1.0.36-unstable.2) (2019-05-31) - - +## [1.0.36-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.36-unstable.1...@aws-amplify/api@1.0.36-unstable.2) (2019-05-31) **Note:** Version bump only for package @aws-amplify/api -## [1.0.36-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.35...@aws-amplify/api@1.0.36-unstable.1) (2019-05-24) +## [1.0.36-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.35...@aws-amplify/api@1.0.36-unstable.1) (2019-05-24) ### Bug Fixes -* **aws-amplify:** manual version bumps for lerna issue ([9ce5a72](https://github.com/aws/aws-amplify/commit/9ce5a72)) - - - +- **aws-amplify:** manual version bumps for lerna issue ([9ce5a72](https://github.com/aws/aws-amplify/commit/9ce5a72)) -## [1.0.35](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.35-unstable.2...@aws-amplify/api@1.0.35) (2019-05-14) - - +## [1.0.35](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.35-unstable.2...@aws-amplify/api@1.0.35) (2019-05-14) **Note:** Version bump only for package @aws-amplify/api -## [1.0.35-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.35-unstable.1...@aws-amplify/api@1.0.35-unstable.2) (2019-05-14) - - +## [1.0.35-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.35-unstable.1...@aws-amplify/api@1.0.35-unstable.2) (2019-05-14) **Note:** Version bump only for package @aws-amplify/api -## [1.0.35-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.35-unstable.0...@aws-amplify/api@1.0.35-unstable.1) (2019-05-13) - - +## [1.0.35-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.35-unstable.0...@aws-amplify/api@1.0.35-unstable.1) (2019-05-13) **Note:** Version bump only for package @aws-amplify/api -## [1.0.35-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34...@aws-amplify/api@1.0.35-unstable.0) (2019-05-09) - - +## [1.0.35-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34...@aws-amplify/api@1.0.35-unstable.0) (2019-05-09) **Note:** Version bump only for package @aws-amplify/api -## [1.0.34](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.9...@aws-amplify/api@1.0.34) (2019-05-06) - - +## [1.0.34](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.9...@aws-amplify/api@1.0.34) (2019-05-06) **Note:** Version bump only for package @aws-amplify/api -## [1.0.34-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.8...@aws-amplify/api@1.0.34-unstable.9) (2019-05-06) - - +## [1.0.34-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.8...@aws-amplify/api@1.0.34-unstable.9) (2019-05-06) **Note:** Version bump only for package @aws-amplify/api -## [1.0.34-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.7...@aws-amplify/api@1.0.34-unstable.8) (2019-05-06) +## [1.0.34-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.7...@aws-amplify/api@1.0.34-unstable.8) (2019-05-06) ### Features -* **pubsub:** Enable PubSub to work along side GraphQL/Appsync ([d8c972d](https://github.com/aws/aws-amplify/commit/d8c972d)) - - - +- **pubsub:** Enable PubSub to work along side GraphQL/Appsync ([d8c972d](https://github.com/aws/aws-amplify/commit/d8c972d)) -## [1.0.34-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.6...@aws-amplify/api@1.0.34-unstable.7) (2019-04-26) - - +## [1.0.34-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.6...@aws-amplify/api@1.0.34-unstable.7) (2019-04-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.34-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.5...@aws-amplify/api@1.0.34-unstable.6) (2019-04-26) - - +## [1.0.34-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.5...@aws-amplify/api@1.0.34-unstable.6) (2019-04-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.34-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.4...@aws-amplify/api@1.0.34-unstable.5) (2019-04-24) - - +## [1.0.34-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.4...@aws-amplify/api@1.0.34-unstable.5) (2019-04-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.34-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.3...@aws-amplify/api@1.0.34-unstable.4) (2019-04-24) - - +## [1.0.34-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.3...@aws-amplify/api@1.0.34-unstable.4) (2019-04-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.34-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.2...@aws-amplify/api@1.0.34-unstable.3) (2019-04-17) - - +## [1.0.34-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.2...@aws-amplify/api@1.0.34-unstable.3) (2019-04-17) **Note:** Version bump only for package @aws-amplify/api -## [1.0.34-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.1...@aws-amplify/api@1.0.34-unstable.2) (2019-04-16) - - +## [1.0.34-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.1...@aws-amplify/api@1.0.34-unstable.2) (2019-04-16) **Note:** Version bump only for package @aws-amplify/api -## [1.0.34-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.0...@aws-amplify/api@1.0.34-unstable.1) (2019-04-12) - - +## [1.0.34-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.34-unstable.0...@aws-amplify/api@1.0.34-unstable.1) (2019-04-12) **Note:** Version bump only for package @aws-amplify/api -## [1.0.34-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.33...@aws-amplify/api@1.0.34-unstable.0) (2019-04-12) - - +## [1.0.34-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.33...@aws-amplify/api@1.0.34-unstable.0) (2019-04-12) **Note:** Version bump only for package @aws-amplify/api -## [1.0.33](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.33-unstable.0...@aws-amplify/api@1.0.33) (2019-04-11) - - +## [1.0.33](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.33-unstable.0...@aws-amplify/api@1.0.33) (2019-04-11) **Note:** Version bump only for package @aws-amplify/api -## [1.0.33-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.32...@aws-amplify/api@1.0.33-unstable.0) (2019-04-10) - - +## [1.0.33-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.32...@aws-amplify/api@1.0.33-unstable.0) (2019-04-10) **Note:** Version bump only for package @aws-amplify/api -## [1.0.32](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.32-unstable.1...@aws-amplify/api@1.0.32) (2019-04-09) - - +## [1.0.32](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.32-unstable.1...@aws-amplify/api@1.0.32) (2019-04-09) **Note:** Version bump only for package @aws-amplify/api -## [1.0.32-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.32-unstable.0...@aws-amplify/api@1.0.32-unstable.1) (2019-04-08) - - +## [1.0.32-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.32-unstable.0...@aws-amplify/api@1.0.32-unstable.1) (2019-04-08) **Note:** Version bump only for package @aws-amplify/api -## [1.0.32-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.31...@aws-amplify/api@1.0.32-unstable.0) (2019-04-07) - - +## [1.0.32-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.31...@aws-amplify/api@1.0.32-unstable.0) (2019-04-07) **Note:** Version bump only for package @aws-amplify/api -## [1.0.31](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.31-unstable.1...@aws-amplify/api@1.0.31) (2019-04-04) - - +## [1.0.31](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.31-unstable.1...@aws-amplify/api@1.0.31) (2019-04-04) **Note:** Version bump only for package @aws-amplify/api -## [1.0.31-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.31-unstable.0...@aws-amplify/api@1.0.31-unstable.1) (2019-04-04) - - +## [1.0.31-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.31-unstable.0...@aws-amplify/api@1.0.31-unstable.1) (2019-04-04) **Note:** Version bump only for package @aws-amplify/api -## [1.0.31-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30...@aws-amplify/api@1.0.31-unstable.0) (2019-04-02) - - +## [1.0.31-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30...@aws-amplify/api@1.0.31-unstable.0) (2019-04-02) **Note:** Version bump only for package @aws-amplify/api -## [1.0.30](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.7...@aws-amplify/api@1.0.30) (2019-03-28) - - +## [1.0.30](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.7...@aws-amplify/api@1.0.30) (2019-03-28) **Note:** Version bump only for package @aws-amplify/api -## [1.0.30-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.6...@aws-amplify/api@1.0.30-unstable.7) (2019-03-28) - - +## [1.0.30-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.6...@aws-amplify/api@1.0.30-unstable.7) (2019-03-28) **Note:** Version bump only for package @aws-amplify/api -## [1.0.30-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.5...@aws-amplify/api@1.0.30-unstable.6) (2019-03-25) +## [1.0.30-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.5...@aws-amplify/api@1.0.30-unstable.6) (2019-03-25) ### Bug Fixes -* **api:** allow API options to be merged with root level options ([8965b36](https://github.com/aws/aws-amplify/commit/8965b36)), closes [#1302](https://github.com/aws/aws-amplify/issues/1302) - - - +- **api:** allow API options to be merged with root level options ([8965b36](https://github.com/aws/aws-amplify/commit/8965b36)), closes [#1302](https://github.com/aws/aws-amplify/issues/1302) -## [1.0.30-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.4...@aws-amplify/api@1.0.30-unstable.5) (2019-03-24) - - +## [1.0.30-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.4...@aws-amplify/api@1.0.30-unstable.5) (2019-03-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.30-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.3...@aws-amplify/api@1.0.30-unstable.4) (2019-03-22) - - +## [1.0.30-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.3...@aws-amplify/api@1.0.30-unstable.4) (2019-03-22) **Note:** Version bump only for package @aws-amplify/api -## [1.0.30-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.2...@aws-amplify/api@1.0.30-unstable.3) (2019-03-22) - - +## [1.0.30-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.2...@aws-amplify/api@1.0.30-unstable.3) (2019-03-22) **Note:** Version bump only for package @aws-amplify/api -## [1.0.30-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.1...@aws-amplify/api@1.0.30-unstable.2) (2019-03-20) - - +## [1.0.30-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.1...@aws-amplify/api@1.0.30-unstable.2) (2019-03-20) **Note:** Version bump only for package @aws-amplify/api -## [1.0.30-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.0...@aws-amplify/api@1.0.30-unstable.1) (2019-03-19) - - +## [1.0.30-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.30-unstable.0...@aws-amplify/api@1.0.30-unstable.1) (2019-03-19) **Note:** Version bump only for package @aws-amplify/api -## [1.0.30-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.29...@aws-amplify/api@1.0.30-unstable.0) (2019-03-18) - - +## [1.0.30-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.29...@aws-amplify/api@1.0.30-unstable.0) (2019-03-18) **Note:** Version bump only for package @aws-amplify/api -## [1.0.29](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.29-unstable.1...@aws-amplify/api@1.0.29) (2019-03-06) - - +## [1.0.29](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.29-unstable.1...@aws-amplify/api@1.0.29) (2019-03-06) **Note:** Version bump only for package @aws-amplify/api -## [1.0.29-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.29-unstable.0...@aws-amplify/api@1.0.29-unstable.1) (2019-03-06) - - +## [1.0.29-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.29-unstable.0...@aws-amplify/api@1.0.29-unstable.1) (2019-03-06) **Note:** Version bump only for package @aws-amplify/api -## [1.0.29-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.28...@aws-amplify/api@1.0.29-unstable.0) (2019-03-04) - - +## [1.0.29-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.28...@aws-amplify/api@1.0.29-unstable.0) (2019-03-04) **Note:** Version bump only for package @aws-amplify/api -## [1.0.28](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27...@aws-amplify/api@1.0.28) (2019-03-04) - - +## [1.0.28](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27...@aws-amplify/api@1.0.28) (2019-03-04) **Note:** Version bump only for package @aws-amplify/api -## [1.0.27](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.8...@aws-amplify/api@1.0.27) (2019-03-04) - - +## [1.0.27](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.8...@aws-amplify/api@1.0.27) (2019-03-04) **Note:** Version bump only for package @aws-amplify/api -## [1.0.27-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.7...@aws-amplify/api@1.0.27-unstable.8) (2019-03-04) - - +## [1.0.27-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.7...@aws-amplify/api@1.0.27-unstable.8) (2019-03-04) **Note:** Version bump only for package @aws-amplify/api -## [1.0.27-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.6...@aws-amplify/api@1.0.27-unstable.7) (2019-03-04) - - +## [1.0.27-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.6...@aws-amplify/api@1.0.27-unstable.7) (2019-03-04) **Note:** Version bump only for package @aws-amplify/api -## [1.0.27-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.5...@aws-amplify/api@1.0.27-unstable.6) (2019-03-01) - - +## [1.0.27-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.5...@aws-amplify/api@1.0.27-unstable.6) (2019-03-01) **Note:** Version bump only for package @aws-amplify/api -## [1.0.27-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.4...@aws-amplify/api@1.0.27-unstable.5) (2019-02-27) - - +## [1.0.27-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.4...@aws-amplify/api@1.0.27-unstable.5) (2019-02-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.27-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.3...@aws-amplify/api@1.0.27-unstable.4) (2019-02-27) - - +## [1.0.27-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.3...@aws-amplify/api@1.0.27-unstable.4) (2019-02-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.27-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.2...@aws-amplify/api@1.0.27-unstable.3) (2019-01-21) - - +## [1.0.27-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.2...@aws-amplify/api@1.0.27-unstable.3) (2019-01-21) **Note:** Version bump only for package @aws-amplify/api -## [1.0.27-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.1...@aws-amplify/api@1.0.27-unstable.2) (2019-01-18) - - +## [1.0.27-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.1...@aws-amplify/api@1.0.27-unstable.2) (2019-01-18) **Note:** Version bump only for package @aws-amplify/api -## [1.0.27-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.0...@aws-amplify/api@1.0.27-unstable.1) (2019-01-10) - - +## [1.0.27-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.27-unstable.0...@aws-amplify/api@1.0.27-unstable.1) (2019-01-10) **Note:** Version bump only for package @aws-amplify/api -## [1.0.27-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.26...@aws-amplify/api@1.0.27-unstable.0) (2019-01-10) - - +## [1.0.27-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.26...@aws-amplify/api@1.0.27-unstable.0) (2019-01-10) **Note:** Version bump only for package @aws-amplify/api -## [1.0.26](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.26-unstable.0...@aws-amplify/api@1.0.26) (2019-01-10) - - +## [1.0.26](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.26-unstable.0...@aws-amplify/api@1.0.26) (2019-01-10) **Note:** Version bump only for package @aws-amplify/api -## [1.0.26-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.25...@aws-amplify/api@1.0.26-unstable.0) (2018-12-26) - - +## [1.0.26-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.25...@aws-amplify/api@1.0.26-unstable.0) (2018-12-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.25](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.25-unstable.2...@aws-amplify/api@1.0.25) (2018-12-26) - - +## [1.0.25](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.25-unstable.2...@aws-amplify/api@1.0.25) (2018-12-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.25-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.25-unstable.1...@aws-amplify/api@1.0.25-unstable.2) (2018-12-22) - - +## [1.0.25-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.25-unstable.1...@aws-amplify/api@1.0.25-unstable.2) (2018-12-22) **Note:** Version bump only for package @aws-amplify/api -## [1.0.25-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.25-unstable.0...@aws-amplify/api@1.0.25-unstable.1) (2018-12-20) - - +## [1.0.25-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.25-unstable.0...@aws-amplify/api@1.0.25-unstable.1) (2018-12-20) **Note:** Version bump only for package @aws-amplify/api -## [1.0.25-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.24...@aws-amplify/api@1.0.25-unstable.0) (2018-12-19) - - +## [1.0.25-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.24...@aws-amplify/api@1.0.25-unstable.0) (2018-12-19) **Note:** Version bump only for package @aws-amplify/api -## [1.0.24](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.24-unstable.3...@aws-amplify/api@1.0.24) (2018-12-13) - - +## [1.0.24](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.24-unstable.3...@aws-amplify/api@1.0.24) (2018-12-13) **Note:** Version bump only for package @aws-amplify/api -## [1.0.24-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.24-unstable.2...@aws-amplify/api@1.0.24-unstable.3) (2018-12-13) - - +## [1.0.24-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.24-unstable.2...@aws-amplify/api@1.0.24-unstable.3) (2018-12-13) **Note:** Version bump only for package @aws-amplify/api -## [1.0.24-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.24-unstable.1...@aws-amplify/api@1.0.24-unstable.2) (2018-12-13) - - +## [1.0.24-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.24-unstable.1...@aws-amplify/api@1.0.24-unstable.2) (2018-12-13) **Note:** Version bump only for package @aws-amplify/api -## [1.0.24-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.24-unstable.0...@aws-amplify/api@1.0.24-unstable.1) (2018-12-07) - - +## [1.0.24-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.24-unstable.0...@aws-amplify/api@1.0.24-unstable.1) (2018-12-07) **Note:** Version bump only for package @aws-amplify/api -## [1.0.24-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.23...@aws-amplify/api@1.0.24-unstable.0) (2018-12-07) - - +## [1.0.24-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.23...@aws-amplify/api@1.0.24-unstable.0) (2018-12-07) **Note:** Version bump only for package @aws-amplify/api -## [1.0.23](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22...@aws-amplify/api@1.0.23) (2018-12-07) - - +## [1.0.23](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22...@aws-amplify/api@1.0.23) (2018-12-07) **Note:** Version bump only for package @aws-amplify/api -## [1.0.23-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22...@aws-amplify/api@1.0.23-unstable.0) (2018-12-07) - - +## [1.0.23-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22...@aws-amplify/api@1.0.23-unstable.0) (2018-12-07) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.12...@aws-amplify/api@1.0.22) (2018-12-03) - - +## [1.0.22](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.12...@aws-amplify/api@1.0.22) (2018-12-03) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22-unstable.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.11...@aws-amplify/api@1.0.22-unstable.12) (2018-12-03) +## [1.0.22-unstable.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.11...@aws-amplify/api@1.0.22-unstable.12) (2018-12-03) ### Features -* **@aws-amplify/api,graphql:** DocumentNode support for GraphQL Client ([#2227](https://github.com/aws/aws-amplify/issues/2227)) ([f31d649](https://github.com/aws/aws-amplify/commit/f31d649)), closes [#1237](https://github.com/aws/aws-amplify/issues/1237) - - - +- **@aws-amplify/api,graphql:** DocumentNode support for GraphQL Client ([#2227](https://github.com/aws/aws-amplify/issues/2227)) ([f31d649](https://github.com/aws/aws-amplify/commit/f31d649)), closes [#1237](https://github.com/aws/aws-amplify/issues/1237) -## [1.0.22-unstable.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.10...@aws-amplify/api@1.0.22-unstable.11) (2018-11-27) - - +## [1.0.22-unstable.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.10...@aws-amplify/api@1.0.22-unstable.11) (2018-11-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.9...@aws-amplify/api@1.0.22-unstable.10) (2018-11-26) - - +## [1.0.22-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.9...@aws-amplify/api@1.0.22-unstable.10) (2018-11-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.8...@aws-amplify/api@1.0.22-unstable.9) (2018-11-23) - - +## [1.0.22-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.8...@aws-amplify/api@1.0.22-unstable.9) (2018-11-23) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.7...@aws-amplify/api@1.0.22-unstable.8) (2018-11-20) - - - -**Note:** Version bump only for package @aws-amplify/api - - -## [1.0.22-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.6...@aws-amplify/api@1.0.22-unstable.7) (2018-11-19) +## [1.0.22-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.7...@aws-amplify/api@1.0.22-unstable.8) (2018-11-20) +**Note:** Version bump only for package @aws-amplify/api + +## [1.0.22-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.6...@aws-amplify/api@1.0.22-unstable.7) (2018-11-19) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.5...@aws-amplify/api@1.0.22-unstable.6) (2018-11-19) - - +## [1.0.22-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.5...@aws-amplify/api@1.0.22-unstable.6) (2018-11-19) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.4...@aws-amplify/api@1.0.22-unstable.5) (2018-11-19) - - +## [1.0.22-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.4...@aws-amplify/api@1.0.22-unstable.5) (2018-11-19) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.3...@aws-amplify/api@1.0.22-unstable.4) (2018-11-17) - - +## [1.0.22-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.3...@aws-amplify/api@1.0.22-unstable.4) (2018-11-17) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.2...@aws-amplify/api@1.0.22-unstable.3) (2018-11-16) - - +## [1.0.22-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.2...@aws-amplify/api@1.0.22-unstable.3) (2018-11-16) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.1...@aws-amplify/api@1.0.22-unstable.2) (2018-11-16) - - +## [1.0.22-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.1...@aws-amplify/api@1.0.22-unstable.2) (2018-11-16) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.0...@aws-amplify/api@1.0.22-unstable.1) (2018-11-15) - - +## [1.0.22-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.22-unstable.0...@aws-amplify/api@1.0.22-unstable.1) (2018-11-15) **Note:** Version bump only for package @aws-amplify/api -## [1.0.22-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.21...@aws-amplify/api@1.0.22-unstable.0) (2018-11-13) - - +## [1.0.22-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.21...@aws-amplify/api@1.0.22-unstable.0) (2018-11-13) **Note:** Version bump only for package @aws-amplify/api -## [1.0.21](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.21-unstable.1...@aws-amplify/api@1.0.21) (2018-11-12) - - +## [1.0.21](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.21-unstable.1...@aws-amplify/api@1.0.21) (2018-11-12) **Note:** Version bump only for package @aws-amplify/api -## [1.0.21-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.21-unstable.0...@aws-amplify/api@1.0.21-unstable.1) (2018-11-09) - - +## [1.0.21-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.21-unstable.0...@aws-amplify/api@1.0.21-unstable.1) (2018-11-09) **Note:** Version bump only for package @aws-amplify/api -## [1.0.21-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.20...@aws-amplify/api@1.0.21-unstable.0) (2018-11-06) - - +## [1.0.21-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.20...@aws-amplify/api@1.0.21-unstable.0) (2018-11-06) **Note:** Version bump only for package @aws-amplify/api -## [1.0.20](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.20-unstable.0...@aws-amplify/api@1.0.20) (2018-11-01) - - +## [1.0.20](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.20-unstable.0...@aws-amplify/api@1.0.20) (2018-11-01) **Note:** Version bump only for package @aws-amplify/api -## [1.0.20-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.19...@aws-amplify/api@1.0.20-unstable.0) (2018-10-30) - - +## [1.0.20-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.19...@aws-amplify/api@1.0.20-unstable.0) (2018-10-30) **Note:** Version bump only for package @aws-amplify/api -## [1.0.19](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.19-unstable.1...@aws-amplify/api@1.0.19) (2018-10-29) - - +## [1.0.19](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.19-unstable.1...@aws-amplify/api@1.0.19) (2018-10-29) **Note:** Version bump only for package @aws-amplify/api -## [1.0.19-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.19-unstable.0...@aws-amplify/api@1.0.19-unstable.1) (2018-10-29) - - +## [1.0.19-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.19-unstable.0...@aws-amplify/api@1.0.19-unstable.1) (2018-10-29) **Note:** Version bump only for package @aws-amplify/api -## [1.0.19-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.18...@aws-amplify/api@1.0.19-unstable.0) (2018-10-29) - - +## [1.0.19-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.18...@aws-amplify/api@1.0.19-unstable.0) (2018-10-29) **Note:** Version bump only for package @aws-amplify/api -## [1.0.18](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.18-unstable.3...@aws-amplify/api@1.0.18) (2018-10-17) - - +## [1.0.18](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.18-unstable.3...@aws-amplify/api@1.0.18) (2018-10-17) **Note:** Version bump only for package @aws-amplify/api -## [1.0.18-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.18-unstable.2...@aws-amplify/api@1.0.18-unstable.3) (2018-10-16) - - +## [1.0.18-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.18-unstable.2...@aws-amplify/api@1.0.18-unstable.3) (2018-10-16) **Note:** Version bump only for package @aws-amplify/api -## [1.0.18-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.18-unstable.1...@aws-amplify/api@1.0.18-unstable.2) (2018-10-08) - - +## [1.0.18-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.18-unstable.1...@aws-amplify/api@1.0.18-unstable.2) (2018-10-08) **Note:** Version bump only for package @aws-amplify/api -## [1.0.18-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.18-unstable.0...@aws-amplify/api@1.0.18-unstable.1) (2018-10-05) - - +## [1.0.18-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.18-unstable.0...@aws-amplify/api@1.0.18-unstable.1) (2018-10-05) **Note:** Version bump only for package @aws-amplify/api -## [1.0.18-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.17-unstable.1...@aws-amplify/api@1.0.18-unstable.0) (2018-10-05) - - +## [1.0.18-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.17-unstable.1...@aws-amplify/api@1.0.18-unstable.0) (2018-10-05) **Note:** Version bump only for package @aws-amplify/api -## [1.0.17](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.17-unstable.1...@aws-amplify/api@1.0.17) (2018-10-04) - - +## [1.0.17](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.17-unstable.1...@aws-amplify/api@1.0.17) (2018-10-04) **Note:** Version bump only for package @aws-amplify/api -## [1.0.17-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.17-unstable.0...@aws-amplify/api@1.0.17-unstable.1) (2018-10-03) - - +## [1.0.17-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.17-unstable.0...@aws-amplify/api@1.0.17-unstable.1) (2018-10-03) **Note:** Version bump only for package @aws-amplify/api -## [1.0.17-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.4...@aws-amplify/api@1.0.17-unstable.0) (2018-10-03) - - +## [1.0.17-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.4...@aws-amplify/api@1.0.17-unstable.0) (2018-10-03) **Note:** Version bump only for package @aws-amplify/api -## [1.0.16](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.4...@aws-amplify/api@1.0.16) (2018-10-03) - - +## [1.0.16](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.4...@aws-amplify/api@1.0.16) (2018-10-03) **Note:** Version bump only for package @aws-amplify/api -## [1.0.16-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.3...@aws-amplify/api@1.0.16-unstable.4) (2018-10-01) - - +## [1.0.16-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.3...@aws-amplify/api@1.0.16-unstable.4) (2018-10-01) **Note:** Version bump only for package @aws-amplify/api -## [1.0.16-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.2...@aws-amplify/api@1.0.16-unstable.3) (2018-09-28) - - +## [1.0.16-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.2...@aws-amplify/api@1.0.16-unstable.3) (2018-09-28) **Note:** Version bump only for package @aws-amplify/api -## [1.0.16-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.1...@aws-amplify/api@1.0.16-unstable.2) (2018-09-27) - - +## [1.0.16-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.1...@aws-amplify/api@1.0.16-unstable.2) (2018-09-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.16-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.0...@aws-amplify/api@1.0.16-unstable.1) (2018-09-27) - - +## [1.0.16-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.16-unstable.0...@aws-amplify/api@1.0.16-unstable.1) (2018-09-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.16-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15...@aws-amplify/api@1.0.16-unstable.0) (2018-09-27) - - +## [1.0.16-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15...@aws-amplify/api@1.0.16-unstable.0) (2018-09-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.9...@aws-amplify/api@1.0.15) (2018-09-27) - - +## [1.0.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.9...@aws-amplify/api@1.0.15) (2018-09-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.15-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.8...@aws-amplify/api@1.0.15-unstable.9) (2018-09-26) - - +## [1.0.15-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.8...@aws-amplify/api@1.0.15-unstable.9) (2018-09-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.15-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.7...@aws-amplify/api@1.0.15-unstable.8) (2018-09-26) - - +## [1.0.15-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.7...@aws-amplify/api@1.0.15-unstable.8) (2018-09-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.15-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.6...@aws-amplify/api@1.0.15-unstable.7) (2018-09-26) - - +## [1.0.15-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.6...@aws-amplify/api@1.0.15-unstable.7) (2018-09-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.15-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.4...@aws-amplify/api@1.0.15-unstable.6) (2018-09-26) - - +## [1.0.15-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.4...@aws-amplify/api@1.0.15-unstable.6) (2018-09-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.15-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.4...@aws-amplify/api@1.0.15-unstable.5) (2018-09-25) - - +## [1.0.15-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.4...@aws-amplify/api@1.0.15-unstable.5) (2018-09-25) **Note:** Version bump only for package @aws-amplify/api -## [1.0.15-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.3...@aws-amplify/api@1.0.15-unstable.4) (2018-09-25) - - +## [1.0.15-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.3...@aws-amplify/api@1.0.15-unstable.4) (2018-09-25) **Note:** Version bump only for package @aws-amplify/api -## [1.0.15-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.2...@aws-amplify/api@1.0.15-unstable.3) (2018-09-24) - - +## [1.0.15-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.2...@aws-amplify/api@1.0.15-unstable.3) (2018-09-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.15-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.1...@aws-amplify/api@1.0.15-unstable.2) (2018-09-22) - - +## [1.0.15-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.1...@aws-amplify/api@1.0.15-unstable.2) (2018-09-22) **Note:** Version bump only for package @aws-amplify/api -## [1.0.15-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.0...@aws-amplify/api@1.0.15-unstable.1) (2018-09-22) +## [1.0.15-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.15-unstable.0...@aws-amplify/api@1.0.15-unstable.1) (2018-09-22) ### Bug Fixes -* **pubsub,api-test:** Do not disconnect active mqtt connections when establishing new ones. ([#1649](https://github.com/aws/aws-amplify/issues/1649)) ([b19d688](https://github.com/aws/aws-amplify/commit/b19d688)) - - - +- **pubsub,api-test:** Do not disconnect active mqtt connections when establishing new ones. ([#1649](https://github.com/aws/aws-amplify/issues/1649)) ([b19d688](https://github.com/aws/aws-amplify/commit/b19d688)) -## [1.0.15-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.14...@aws-amplify/api@1.0.15-unstable.0) (2018-09-22) +## [1.0.15-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.14...@aws-amplify/api@1.0.15-unstable.0) (2018-09-22) ### Bug Fixes -* **@aws-amplify/api:** Content-Type header on init options ([#1720](https://github.com/aws/aws-amplify/issues/1720)) ([dbe37e0](https://github.com/aws/aws-amplify/commit/dbe37e0)) - - - +- **@aws-amplify/api:** Content-Type header on init options ([#1720](https://github.com/aws/aws-amplify/issues/1720)) ([dbe37e0](https://github.com/aws/aws-amplify/commit/dbe37e0)) -## [1.0.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.14-unstable.0...@aws-amplify/api@1.0.14) (2018-09-21) - - +## [1.0.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.14-unstable.0...@aws-amplify/api@1.0.14) (2018-09-21) **Note:** Version bump only for package @aws-amplify/api -## [1.0.14-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.13-unstable.3...@aws-amplify/api@1.0.14-unstable.0) (2018-09-21) +## [1.0.14-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.13-unstable.3...@aws-amplify/api@1.0.14-unstable.0) (2018-09-21) ### Bug Fixes -* **@aws-amplify/api:** send websocket disconnect errors thru observable and add paho client on vendor ([#1698](https://github.com/aws/aws-amplify/issues/1698)) ([72c6b4b](https://github.com/aws/aws-amplify/commit/72c6b4b)) -* bumping version for deploying on unstable tag ([#1706](https://github.com/aws/aws-amplify/issues/1706)) ([b5d6468](https://github.com/aws/aws-amplify/commit/b5d6468)) - - - +- **@aws-amplify/api:** send websocket disconnect errors thru observable and add paho client on vendor ([#1698](https://github.com/aws/aws-amplify/issues/1698)) ([72c6b4b](https://github.com/aws/aws-amplify/commit/72c6b4b)) +- bumping version for deploying on unstable tag ([#1706](https://github.com/aws/aws-amplify/issues/1706)) ([b5d6468](https://github.com/aws/aws-amplify/commit/b5d6468)) -## [1.0.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.12...@aws-amplify/api@1.0.13) (2018-09-21) - - +## [1.0.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.12...@aws-amplify/api@1.0.13) (2018-09-21) **Note:** Version bump only for package @aws-amplify/api -## [1.0.13-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.13-unstable.2...@aws-amplify/api@1.0.13-unstable.3) (2018-09-20) - - +## [1.0.13-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.13-unstable.2...@aws-amplify/api@1.0.13-unstable.3) (2018-09-20) **Note:** Version bump only for package @aws-amplify/api -## [1.0.13-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.13-unstable.1...@aws-amplify/api@1.0.13-unstable.2) (2018-09-20) - - +## [1.0.13-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.13-unstable.1...@aws-amplify/api@1.0.13-unstable.2) (2018-09-20) **Note:** Version bump only for package @aws-amplify/api -## [1.0.13-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.13-unstable.0...@aws-amplify/api@1.0.13-unstable.1) (2018-09-17) - - +## [1.0.13-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.13-unstable.0...@aws-amplify/api@1.0.13-unstable.1) (2018-09-17) **Note:** Version bump only for package @aws-amplify/api -## [1.0.13-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.12...@aws-amplify/api@1.0.13-unstable.0) (2018-09-17) - - +## [1.0.13-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.12...@aws-amplify/api@1.0.13-unstable.0) (2018-09-17) **Note:** Version bump only for package @aws-amplify/api -## [1.0.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.11...@aws-amplify/api@1.0.12) (2018-09-17) +## [1.0.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.11...@aws-amplify/api@1.0.12) (2018-09-17) ### Bug Fixes -* **pubsub,api,appsync:** Use subscriber-id header (AppSync subscription) ([#1618](https://github.com/aws/aws-amplify/issues/1618)) ([03f2517](https://github.com/aws/aws-amplify/commit/03f2517)) - - - +- **pubsub,api,appsync:** Use subscriber-id header (AppSync subscription) ([#1618](https://github.com/aws/aws-amplify/issues/1618)) ([03f2517](https://github.com/aws/aws-amplify/commit/03f2517)) -## [1.0.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.10...@aws-amplify/api@1.0.11) (2018-09-12) +## [1.0.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.10...@aws-amplify/api@1.0.11) (2018-09-12) ### Bug Fixes -* **pubsub:** Better handling of multiple AppSync subscriptions ([#1611](https://github.com/aws/aws-amplify/issues/1611)) ([6c86500](https://github.com/aws/aws-amplify/commit/6c86500)) - - - +- **pubsub:** Better handling of multiple AppSync subscriptions ([#1611](https://github.com/aws/aws-amplify/issues/1611)) ([6c86500](https://github.com/aws/aws-amplify/commit/6c86500)) -## [1.0.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.10-unstable.0...@aws-amplify/api@1.0.10) (2018-09-09) - - +## [1.0.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.10-unstable.0...@aws-amplify/api@1.0.10) (2018-09-09) **Note:** Version bump only for package @aws-amplify/api -## [1.0.10-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.9...@aws-amplify/api@1.0.10-unstable.0) (2018-09-09) - - +## [1.0.10-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.9...@aws-amplify/api@1.0.10-unstable.0) (2018-09-09) **Note:** Version bump only for package @aws-amplify/api -## [1.0.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.8...@aws-amplify/api@1.0.9) (2018-09-09) - - +## [1.0.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.8...@aws-amplify/api@1.0.9) (2018-09-09) **Note:** Version bump only for package @aws-amplify/api -## [1.0.9-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.8...@aws-amplify/api@1.0.9-unstable.1) (2018-08-30) - - +## [1.0.9-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.8...@aws-amplify/api@1.0.9-unstable.1) (2018-08-30) **Note:** Version bump only for package @aws-amplify/api -## [1.0.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.26...@aws-amplify/api@1.0.8) (2018-08-28) - - +## [1.0.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.26...@aws-amplify/api@1.0.8) (2018-08-28) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.26](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.25...@aws-amplify/api@1.0.7-unstable.26) (2018-08-28) - - +## [1.0.7-unstable.26](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.25...@aws-amplify/api@1.0.7-unstable.26) (2018-08-28) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.25](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.24...@aws-amplify/api@1.0.7-unstable.25) (2018-08-27) - - +## [1.0.7-unstable.25](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.24...@aws-amplify/api@1.0.7-unstable.25) (2018-08-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.24](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.23...@aws-amplify/api@1.0.7-unstable.24) (2018-08-27) - - +## [1.0.7-unstable.24](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.23...@aws-amplify/api@1.0.7-unstable.24) (2018-08-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.23](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.21...@aws-amplify/api@1.0.7-unstable.23) (2018-08-27) - - +## [1.0.7-unstable.23](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.21...@aws-amplify/api@1.0.7-unstable.23) (2018-08-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.22](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.21...@aws-amplify/api@1.0.7-unstable.22) (2018-08-25) - - +## [1.0.7-unstable.22](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.21...@aws-amplify/api@1.0.7-unstable.22) (2018-08-25) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.21](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.20...@aws-amplify/api@1.0.7-unstable.21) (2018-08-24) - - +## [1.0.7-unstable.21](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.20...@aws-amplify/api@1.0.7-unstable.21) (2018-08-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.20](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.19...@aws-amplify/api@1.0.7-unstable.20) (2018-08-24) - - +## [1.0.7-unstable.20](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.19...@aws-amplify/api@1.0.7-unstable.20) (2018-08-24) **Note:** Version bump only for package @aws-amplify/api - -## [1.0.7-unstable.19](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.17...@aws-amplify/api@1.0.7-unstable.19) (2018-08-24) - - + +## [1.0.7-unstable.19](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.17...@aws-amplify/api@1.0.7-unstable.19) (2018-08-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.18](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.17...@aws-amplify/api@1.0.7-unstable.18) (2018-08-24) - - +## [1.0.7-unstable.18](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.17...@aws-amplify/api@1.0.7-unstable.18) (2018-08-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.17](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.15...@aws-amplify/api@1.0.7-unstable.17) (2018-08-24) - - +## [1.0.7-unstable.17](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.15...@aws-amplify/api@1.0.7-unstable.17) (2018-08-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.16](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.15...@aws-amplify/api@1.0.7-unstable.16) (2018-08-24) - - +## [1.0.7-unstable.16](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.15...@aws-amplify/api@1.0.7-unstable.16) (2018-08-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.14...@aws-amplify/api@1.0.7-unstable.15) (2018-08-24) - - +## [1.0.7-unstable.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.14...@aws-amplify/api@1.0.7-unstable.15) (2018-08-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.13...@aws-amplify/api@1.0.7-unstable.14) (2018-08-24) - - +## [1.0.7-unstable.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.13...@aws-amplify/api@1.0.7-unstable.14) (2018-08-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.11...@aws-amplify/api@1.0.7-unstable.13) (2018-08-23) - - +## [1.0.7-unstable.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.11...@aws-amplify/api@1.0.7-unstable.13) (2018-08-23) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.11...@aws-amplify/api@1.0.7-unstable.12) (2018-08-23) - - +## [1.0.7-unstable.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.11...@aws-amplify/api@1.0.7-unstable.12) (2018-08-23) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.10...@aws-amplify/api@1.0.7-unstable.11) (2018-08-23) - - +## [1.0.7-unstable.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.10...@aws-amplify/api@1.0.7-unstable.11) (2018-08-23) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.9...@aws-amplify/api@1.0.7-unstable.10) (2018-08-23) - - +## [1.0.7-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.9...@aws-amplify/api@1.0.7-unstable.10) (2018-08-23) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.8...@aws-amplify/api@1.0.7-unstable.9) (2018-08-23) - - +## [1.0.7-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.8...@aws-amplify/api@1.0.7-unstable.9) (2018-08-23) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.7...@aws-amplify/api@1.0.7-unstable.8) (2018-08-22) - - +## [1.0.7-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.7...@aws-amplify/api@1.0.7-unstable.8) (2018-08-22) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.6...@aws-amplify/api@1.0.7-unstable.7) (2018-08-22) - - +## [1.0.7-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.6...@aws-amplify/api@1.0.7-unstable.7) (2018-08-22) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.5...@aws-amplify/api@1.0.7-unstable.6) (2018-08-21) - - +## [1.0.7-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.5...@aws-amplify/api@1.0.7-unstable.6) (2018-08-21) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.4...@aws-amplify/api@1.0.7-unstable.5) (2018-08-21) - - +## [1.0.7-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.4...@aws-amplify/api@1.0.7-unstable.5) (2018-08-21) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.3...@aws-amplify/api@1.0.7-unstable.4) (2018-08-20) - - +## [1.0.7-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.3...@aws-amplify/api@1.0.7-unstable.4) (2018-08-20) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.2...@aws-amplify/api@1.0.7-unstable.3) (2018-08-19) +## [1.0.7-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.2...@aws-amplify/api@1.0.7-unstable.3) (2018-08-19) ### Bug Fixes -* **aws-amplify-angular:** Angular rollup ([#1441](https://github.com/aws/aws-amplify/issues/1441)) ([eb84e01](https://github.com/aws/aws-amplify/commit/eb84e01)) - - - +- **aws-amplify-angular:** Angular rollup ([#1441](https://github.com/aws/aws-amplify/issues/1441)) ([eb84e01](https://github.com/aws/aws-amplify/commit/eb84e01)) -## [1.0.7-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.1...@aws-amplify/api@1.0.7-unstable.2) (2018-08-18) - - +## [1.0.7-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.1...@aws-amplify/api@1.0.7-unstable.2) (2018-08-18) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.0...@aws-amplify/api@1.0.7-unstable.1) (2018-08-16) - - +## [1.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.7-unstable.0...@aws-amplify/api@1.0.7-unstable.1) (2018-08-16) **Note:** Version bump only for package @aws-amplify/api -## [1.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6...@aws-amplify/api@1.0.7-unstable.0) (2018-08-15) - - +## [1.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6...@aws-amplify/api@1.0.7-unstable.0) (2018-08-15) **Note:** Version bump only for package @aws-amplify/api -## [1.0.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.5...@aws-amplify/api@1.0.6) (2018-08-14) - - +## [1.0.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.5...@aws-amplify/api@1.0.6) (2018-08-14) **Note:** Version bump only for package @aws-amplify/api -## [1.0.6-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.4...@aws-amplify/api@1.0.6-unstable.5) (2018-08-14) - - +## [1.0.6-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.4...@aws-amplify/api@1.0.6-unstable.5) (2018-08-14) **Note:** Version bump only for package @aws-amplify/api -## [1.0.6-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.3...@aws-amplify/api@1.0.6-unstable.4) (2018-08-13) - - +## [1.0.6-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.3...@aws-amplify/api@1.0.6-unstable.4) (2018-08-13) **Note:** Version bump only for package @aws-amplify/api -## [1.0.6-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.2...@aws-amplify/api@1.0.6-unstable.3) (2018-08-13) - - +## [1.0.6-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.2...@aws-amplify/api@1.0.6-unstable.3) (2018-08-13) **Note:** Version bump only for package @aws-amplify/api -## [1.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.1...@aws-amplify/api@1.0.6-unstable.2) (2018-08-09) - - +## [1.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.1...@aws-amplify/api@1.0.6-unstable.2) (2018-08-09) **Note:** Version bump only for package @aws-amplify/api -## [1.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.0...@aws-amplify/api@1.0.6-unstable.1) (2018-08-07) - - +## [1.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.6-unstable.0...@aws-amplify/api@1.0.6-unstable.1) (2018-08-07) **Note:** Version bump only for package @aws-amplify/api -## [1.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5...@aws-amplify/api@1.0.6-unstable.0) (2018-08-07) +## [1.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5...@aws-amplify/api@1.0.6-unstable.0) (2018-08-07) ### Bug Fixes -* **@aws-amplify/api:** error handling for signed requests in RestClient ([#1362](https://github.com/aws/aws-amplify/issues/1362)) ([fbbeffb](https://github.com/aws/aws-amplify/commit/fbbeffb)) - - - +- **@aws-amplify/api:** error handling for signed requests in RestClient ([#1362](https://github.com/aws/aws-amplify/issues/1362)) ([fbbeffb](https://github.com/aws/aws-amplify/commit/fbbeffb)) -## [1.0.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.7...@aws-amplify/api@1.0.5) (2018-08-06) - - +## [1.0.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.7...@aws-amplify/api@1.0.5) (2018-08-06) **Note:** Version bump only for package @aws-amplify/api -## [1.0.5-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.6...@aws-amplify/api@1.0.5-unstable.7) (2018-08-06) - - +## [1.0.5-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.6...@aws-amplify/api@1.0.5-unstable.7) (2018-08-06) **Note:** Version bump only for package @aws-amplify/api -## [1.0.5-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.5...@aws-amplify/api@1.0.5-unstable.6) (2018-08-06) - - +## [1.0.5-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.5...@aws-amplify/api@1.0.5-unstable.6) (2018-08-06) **Note:** Version bump only for package @aws-amplify/api -## [1.0.5-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.3...@aws-amplify/api@1.0.5-unstable.5) (2018-08-06) - - +## [1.0.5-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.3...@aws-amplify/api@1.0.5-unstable.5) (2018-08-06) **Note:** Version bump only for package @aws-amplify/api -## [1.0.5-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.2...@aws-amplify/api@1.0.5-unstable.3) (2018-07-31) - - +## [1.0.5-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.2...@aws-amplify/api@1.0.5-unstable.3) (2018-07-31) **Note:** Version bump only for package @aws-amplify/api -## [1.0.5-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.1...@aws-amplify/api@1.0.5-unstable.2) (2018-07-31) - - +## [1.0.5-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.1...@aws-amplify/api@1.0.5-unstable.2) (2018-07-31) **Note:** Version bump only for package @aws-amplify/api -## [1.0.5-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.0...@aws-amplify/api@1.0.5-unstable.1) (2018-07-30) - - +## [1.0.5-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.5-unstable.0...@aws-amplify/api@1.0.5-unstable.1) (2018-07-30) **Note:** Version bump only for package @aws-amplify/api -## [1.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.4...@aws-amplify/api@1.0.5-unstable.0) (2018-07-30) - - +## [1.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.4...@aws-amplify/api@1.0.5-unstable.0) (2018-07-30) **Note:** Version bump only for package @aws-amplify/api -## [1.0.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.4-unstable.1...@aws-amplify/api@1.0.4) (2018-07-28) - - +## [1.0.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.4-unstable.1...@aws-amplify/api@1.0.4) (2018-07-28) **Note:** Version bump only for package @aws-amplify/api -## [1.0.4-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.4-unstable.0...@aws-amplify/api@1.0.4-unstable.1) (2018-07-28) - - +## [1.0.4-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.4-unstable.0...@aws-amplify/api@1.0.4-unstable.1) (2018-07-28) **Note:** Version bump only for package @aws-amplify/api -## [1.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.14...@aws-amplify/api@1.0.4-unstable.0) (2018-07-27) - - +## [1.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.14...@aws-amplify/api@1.0.4-unstable.0) (2018-07-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.14...@aws-amplify/api@1.0.3-unstable.15) (2018-07-27) - - +## [1.0.3-unstable.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.14...@aws-amplify/api@1.0.3-unstable.15) (2018-07-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.13...@aws-amplify/api@1.0.3-unstable.14) (2018-07-27) - - +## [1.0.3-unstable.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.13...@aws-amplify/api@1.0.3-unstable.14) (2018-07-27) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.12...@aws-amplify/api@1.0.3-unstable.13) (2018-07-26) - - +## [1.0.3-unstable.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.12...@aws-amplify/api@1.0.3-unstable.13) (2018-07-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.11...@aws-amplify/api@1.0.3-unstable.12) (2018-07-26) - - +## [1.0.3-unstable.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.11...@aws-amplify/api@1.0.3-unstable.12) (2018-07-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.10...@aws-amplify/api@1.0.3-unstable.11) (2018-07-26) - - +## [1.0.3-unstable.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.10...@aws-amplify/api@1.0.3-unstable.11) (2018-07-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.9...@aws-amplify/api@1.0.3-unstable.10) (2018-07-26) - - +## [1.0.3-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.9...@aws-amplify/api@1.0.3-unstable.10) (2018-07-26) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.8...@aws-amplify/api@1.0.3-unstable.9) (2018-07-25) - - +## [1.0.3-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.8...@aws-amplify/api@1.0.3-unstable.9) (2018-07-25) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.7...@aws-amplify/api@1.0.3-unstable.8) (2018-07-25) - - +## [1.0.3-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.7...@aws-amplify/api@1.0.3-unstable.8) (2018-07-25) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.6...@aws-amplify/api@1.0.3-unstable.7) (2018-07-25) - - +## [1.0.3-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.6...@aws-amplify/api@1.0.3-unstable.7) (2018-07-25) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.5...@aws-amplify/api@1.0.3-unstable.6) (2018-07-24) - - +## [1.0.3-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.5...@aws-amplify/api@1.0.3-unstable.6) (2018-07-24) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.4...@aws-amplify/api@1.0.3-unstable.5) (2018-07-23) - - +## [1.0.3-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.4...@aws-amplify/api@1.0.3-unstable.5) (2018-07-23) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.3...@aws-amplify/api@1.0.3-unstable.4) (2018-07-23) - - +## [1.0.3-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.3...@aws-amplify/api@1.0.3-unstable.4) (2018-07-23) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.2...@aws-amplify/api@1.0.3-unstable.3) (2018-07-23) - - +## [1.0.3-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.2...@aws-amplify/api@1.0.3-unstable.3) (2018-07-23) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.1...@aws-amplify/api@1.0.3-unstable.2) (2018-07-20) - - +## [1.0.3-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.1...@aws-amplify/api@1.0.3-unstable.2) (2018-07-20) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.0...@aws-amplify/api@1.0.3-unstable.1) (2018-07-20) - - +## [1.0.3-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.3-unstable.0...@aws-amplify/api@1.0.3-unstable.1) (2018-07-20) **Note:** Version bump only for package @aws-amplify/api -## [1.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.2...@aws-amplify/api@1.0.3-unstable.0) (2018-07-20) - - +## [1.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.2...@aws-amplify/api@1.0.3-unstable.0) (2018-07-20) **Note:** Version bump only for package @aws-amplify/api -## [1.0.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.2-unstable.1...@aws-amplify/api@1.0.2) (2018-07-19) - - +## [1.0.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.2-unstable.1...@aws-amplify/api@1.0.2) (2018-07-19) **Note:** Version bump only for package @aws-amplify/api -## [1.0.2-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1...@aws-amplify/api@1.0.2-unstable.1) (2018-07-19) - - +## [1.0.2-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1...@aws-amplify/api@1.0.2-unstable.1) (2018-07-19) **Note:** Version bump only for package @aws-amplify/api -## [1.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1...@aws-amplify/api@1.0.2-unstable.0) (2018-07-19) - - +## [1.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1...@aws-amplify/api@1.0.2-unstable.0) (2018-07-19) **Note:** Version bump only for package @aws-amplify/api -## [1.0.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1-unstable.4...@aws-amplify/api@1.0.1) (2018-07-18) - - +## [1.0.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1-unstable.4...@aws-amplify/api@1.0.1) (2018-07-18) **Note:** Version bump only for package @aws-amplify/api -## [1.0.1-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1-unstable.3...@aws-amplify/api@1.0.1-unstable.4) (2018-07-18) - - +## [1.0.1-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1-unstable.3...@aws-amplify/api@1.0.1-unstable.4) (2018-07-18) **Note:** Version bump only for package @aws-amplify/api -## [1.0.1-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1-unstable.2...@aws-amplify/api@1.0.1-unstable.3) (2018-07-18) - - +## [1.0.1-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1-unstable.2...@aws-amplify/api@1.0.1-unstable.3) (2018-07-18) **Note:** Version bump only for package @aws-amplify/api -## [1.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1-unstable.1...@aws-amplify/api@1.0.1-unstable.2) (2018-07-18) - - +## [1.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1-unstable.1...@aws-amplify/api@1.0.1-unstable.2) (2018-07-18) **Note:** Version bump only for package @aws-amplify/api -## [1.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1...@aws-amplify/api@1.0.1-unstable.1) (2018-07-18) - - +## [1.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1...@aws-amplify/api@1.0.1-unstable.1) (2018-07-18) **Note:** Version bump only for package @aws-amplify/api -## [1.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1...@aws-amplify/api@1.0.1-unstable.0) (2018-07-18) - - +## [1.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/api@1.0.1...@aws-amplify/api@1.0.1-unstable.0) (2018-07-18) **Note:** Version bump only for package @aws-amplify/api -## 0.1.1-unstable.0 (2018-06-27) - - +## 0.1.1-unstable.0 (2018-06-27) **Note:** Version bump only for package @aws-amplify/api diff --git a/packages/api/__tests__/API-test.ts b/packages/api/__tests__/API-test.ts index 03e75d98888..4b2fa7fd9be 100644 --- a/packages/api/__tests__/API-test.ts +++ b/packages/api/__tests__/API-test.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { CognitoIdentityCredentials } from 'aws-sdk'; import { Signer, Credentials } from '@aws-amplify/core'; -import Auth from '@aws-amplify/auth' +import Auth from '@aws-amplify/auth'; import API, { graphqlOperation } from '../src/API'; import { GRAPHQL_AUTH_MODE } from '../src/types'; import { RestClient } from '../src/RestClient'; @@ -17,55 +17,59 @@ import * as Observable from 'zen-observable'; jest.mock('axios'); const config = { - API: { - region: 'region', - header: {}, - - } + API: { + region: 'region', + header: {}, + }, }; describe('API test', () => { - - afterEach(() => { - jest.restoreAllMocks(); - }); - - const aws_cloud_logic_custom = [{ - "id": "lh3s27sl16", - "name": "todosCRUD", - "description": "", - "endpoint": "https://lh3s27sl16.execute-api.us-east-1.amazonaws.com/Development", - "region": "us-east-1", - "paths": ["/todos", "/todos/123"] - }]; - - describe('graphql test', () => { - test('happy-case-query', async () => { - const spyonAuth = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - - const spyon = jest.spyOn(RestClient.prototype, 'post') - .mockImplementationOnce((url, init) => { - return new Promise((res, rej) => { - res({}) - }); - }); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - apiKey = 'secret_api_key', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: 'API_KEY', - aws_appsync_apiKey: apiKey - }) - const GetEvent = `query GetEvent($id: ID! $nextToken: String) { + afterEach(() => { + jest.restoreAllMocks(); + }); + + const aws_cloud_logic_custom = [ + { + id: 'lh3s27sl16', + name: 'todosCRUD', + description: '', + endpoint: + 'https://lh3s27sl16.execute-api.us-east-1.amazonaws.com/Development', + region: 'us-east-1', + paths: ['/todos', '/todos/123'], + }, + ]; + + describe('graphql test', () => { + test('happy-case-query', async () => { + const spyonAuth = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + + const spyon = jest + .spyOn(RestClient.prototype, 'post') + .mockImplementationOnce((url, init) => { + return new Promise((res, rej) => { + res({}); + }); + }); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + apiKey = 'secret_api_key', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'API_KEY', + aws_appsync_apiKey: apiKey, + }); + const GetEvent = `query GetEvent($id: ID! $nextToken: String) { getEvent(id: $id) { id name @@ -82,59 +86,62 @@ describe('API test', () => { } }`; - const doc = parse(GetEvent); - const query = print(doc); - - const headers = { - Authorization: null, - 'X-Api-Key': apiKey - }; - - const body = { - query, - variables, - }; - - const init = { - headers, - body, - signerServiceInfo: { - service: 'appsync', - region, - } - }; - - await api.graphql(graphqlOperation(GetEvent, variables)); - - expect(spyon).toBeCalledWith(url, init); - }); - - test('happy-case-query-ast', async () => { - const spyonAuth = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - - const spyon = jest.spyOn(RestClient.prototype, 'post') - .mockImplementationOnce((url, init) => { - return new Promise((res, rej) => { - res({}) - }); - }); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - apiKey = 'secret_api_key', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: 'API_KEY', - aws_appsync_apiKey: apiKey - }) - const GetEvent = `query GetEvent($id: ID! $nextToken: String) { + const doc = parse(GetEvent); + const query = print(doc); + + const headers = { + Authorization: null, + 'X-Api-Key': apiKey, + }; + + const body = { + query, + variables, + }; + + const init = { + headers, + body, + signerServiceInfo: { + service: 'appsync', + region, + }, + }; + + await api.graphql(graphqlOperation(GetEvent, variables)); + + expect(spyon).toBeCalledWith(url, init); + }); + + test('happy-case-query-ast', async () => { + const spyonAuth = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + + const spyon = jest + .spyOn(RestClient.prototype, 'post') + .mockImplementationOnce((url, init) => { + return new Promise((res, rej) => { + res({}); + }); + }); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + apiKey = 'secret_api_key', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'API_KEY', + aws_appsync_apiKey: apiKey, + }); + const GetEvent = `query GetEvent($id: ID! $nextToken: String) { getEvent(id: $id) { id name @@ -151,78 +158,85 @@ describe('API test', () => { } }`; - const doc = parse(GetEvent); - const query = print(doc); - - const headers = { - Authorization: null, - 'X-Api-Key': apiKey - }; - - const body = { - query, - variables, - }; - - const init = { - headers, - body, - signerServiceInfo: { - service: 'appsync', - region, - } - }; - - await api.graphql(graphqlOperation(doc, variables)); - - expect(spyon).toBeCalledWith(url, init); - }); - - test('happy-case-query-oidc', async () => { - const spyonAuth = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - - const cognitoCredentialSpyon = jest.spyOn(CognitoIdentityCredentials.prototype, 'get').mockImplementation((callback) => { - callback(null); - }) - - const cache_config = { - capacityInBytes: 3000, - itemMaxSize: 800, - defaultTTL: 3000000, - defaultPriority: 5, - warningThreshold: 0.8, - storage: window.localStorage - }; - - Cache.configure(cache_config); - - const spyonCache = jest.spyOn(Cache, 'getItem').mockImplementationOnce(() => { - return { - token: 'id_token' - } - }); - - const spyon = jest.spyOn(RestClient.prototype, 'post') - .mockImplementationOnce((url, init) => { - return new Promise((res, rej) => { - res({}) - }); - }); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: 'OPENID_CONNECT', - }) - const GetEvent = `query GetEvent($id: ID! $nextToken: String) { + const doc = parse(GetEvent); + const query = print(doc); + + const headers = { + Authorization: null, + 'X-Api-Key': apiKey, + }; + + const body = { + query, + variables, + }; + + const init = { + headers, + body, + signerServiceInfo: { + service: 'appsync', + region, + }, + }; + + await api.graphql(graphqlOperation(doc, variables)); + + expect(spyon).toBeCalledWith(url, init); + }); + + test('happy-case-query-oidc', async () => { + const spyonAuth = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + + const cognitoCredentialSpyon = jest + .spyOn(CognitoIdentityCredentials.prototype, 'get') + .mockImplementation(callback => { + callback(null); + }); + + const cache_config = { + capacityInBytes: 3000, + itemMaxSize: 800, + defaultTTL: 3000000, + defaultPriority: 5, + warningThreshold: 0.8, + storage: window.localStorage, + }; + + Cache.configure(cache_config); + + const spyonCache = jest + .spyOn(Cache, 'getItem') + .mockImplementationOnce(() => { + return { + token: 'id_token', + }; + }); + + const spyon = jest + .spyOn(RestClient.prototype, 'post') + .mockImplementationOnce((url, init) => { + return new Promise((res, rej) => { + res({}); + }); + }); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'OPENID_CONNECT', + }); + const GetEvent = `query GetEvent($id: ID! $nextToken: String) { getEvent(id: $id) { id name @@ -239,62 +253,64 @@ describe('API test', () => { } }`; - const doc = parse(GetEvent); - const query = print(doc); - - const headers = { - Authorization: 'id_token' - }; - - const body = { - query, - variables, - }; - - const init = { - headers, - body, - signerServiceInfo: { - service: 'appsync', - region, - } - }; - - await api.graphql(graphqlOperation(GetEvent, variables)); - - expect(spyon).toBeCalledWith(url, init); - - spyonCache.mockClear(); - }); - - test('multi-auth default case AWS_IAM, using API_KEY as auth mode', async () => { - expect.assertions(1); - - const cache_config = { - capacityInBytes: 3000, - itemMaxSize: 800, - defaultTTL: 3000000, - defaultPriority: 5, - warningThreshold: 0.8, - storage: window.localStorage - }; - - Cache.configure(cache_config); - - const spyon = jest.spyOn(RestClient.prototype, 'post').mockReturnValue(Promise.resolve({})); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, - apiKey = 'secret-api-key'; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: "AWS_IAM", - aws_appsync_apiKey: apiKey - }) - const GetEvent = `query GetEvent($id: ID! $nextToken: String) { + const doc = parse(GetEvent); + const query = print(doc); + + const headers = { + Authorization: 'id_token', + }; + + const body = { + query, + variables, + }; + + const init = { + headers, + body, + signerServiceInfo: { + service: 'appsync', + region, + }, + }; + + await api.graphql(graphqlOperation(GetEvent, variables)); + + expect(spyon).toBeCalledWith(url, init); + + spyonCache.mockClear(); + }); + + test('multi-auth default case AWS_IAM, using API_KEY as auth mode', async () => { + expect.assertions(1); + + const cache_config = { + capacityInBytes: 3000, + itemMaxSize: 800, + defaultTTL: 3000000, + defaultPriority: 5, + warningThreshold: 0.8, + storage: window.localStorage, + }; + + Cache.configure(cache_config); + + const spyon = jest + .spyOn(RestClient.prototype, 'post') + .mockReturnValue(Promise.resolve({})); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, + apiKey = 'secret-api-key'; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'AWS_IAM', + aws_appsync_apiKey: apiKey, + }); + const GetEvent = `query GetEvent($id: ID! $nextToken: String) { getEvent(id: $id) { id name @@ -311,55 +327,62 @@ describe('API test', () => { } }`; - const doc = parse(GetEvent); - const query = print(doc); - - const headers = { - Authorization: null, - 'X-Api-Key': 'secret-api-key' - }; - - const body = { - query, - variables, - }; - - const init = { - headers, - body, - signerServiceInfo: { - service: 'appsync', - region, - } - }; - - await api.graphql({ query: GetEvent, variables, authMode: GRAPHQL_AUTH_MODE.API_KEY }); - - expect(spyon).toBeCalledWith(url, init); - - }); - test('multi-auth default case api-key, using AWS_IAM as auth mode', async () => { - expect.assertions(1); - jest.spyOn(Credentials, 'get').mockReturnValue(Promise.resolve('cred')); - - jest.spyOn(CognitoIdentityCredentials.prototype, 'get').mockImplementation((callback) => { - callback(null); - }) - - const spyon = jest.spyOn(RestClient.prototype, 'post').mockReturnValue(Promise.resolve({})); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, - apiKey = 'secret-api-key'; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: "API_KEY", - aws_appsync_apiKey: apiKey - }) - const GetEvent = `query GetEvent($id: ID! $nextToken: String) { + const doc = parse(GetEvent); + const query = print(doc); + + const headers = { + Authorization: null, + 'X-Api-Key': 'secret-api-key', + }; + + const body = { + query, + variables, + }; + + const init = { + headers, + body, + signerServiceInfo: { + service: 'appsync', + region, + }, + }; + + await api.graphql({ + query: GetEvent, + variables, + authMode: GRAPHQL_AUTH_MODE.API_KEY, + }); + + expect(spyon).toBeCalledWith(url, init); + }); + test('multi-auth default case api-key, using AWS_IAM as auth mode', async () => { + expect.assertions(1); + jest.spyOn(Credentials, 'get').mockReturnValue(Promise.resolve('cred')); + + jest + .spyOn(CognitoIdentityCredentials.prototype, 'get') + .mockImplementation(callback => { + callback(null); + }); + + const spyon = jest + .spyOn(RestClient.prototype, 'post') + .mockReturnValue(Promise.resolve({})); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, + apiKey = 'secret-api-key'; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'API_KEY', + aws_appsync_apiKey: apiKey, + }); + const GetEvent = `query GetEvent($id: ID! $nextToken: String) { getEvent(id: $id) { id name @@ -376,58 +399,64 @@ describe('API test', () => { } }`; - const doc = parse(GetEvent); - const query = print(doc); - - const headers = {}; - - const body = { - query, - variables, - }; - - const init = { - headers, - body, - signerServiceInfo: { - service: 'appsync', - region, - } - }; - - await api.graphql({ query: GetEvent, variables, authMode: GRAPHQL_AUTH_MODE.AWS_IAM }); - - expect(spyon).toBeCalledWith(url, init); - }); - test('multi-auth default case api-key, using OIDC as auth mode', async () => { - expect.assertions(1); - const cache_config = { - capacityInBytes: 3000, - itemMaxSize: 800, - defaultTTL: 3000000, - defaultPriority: 5, - warningThreshold: 0.8, - storage: window.localStorage - }; - - Cache.configure(cache_config); - - jest.spyOn(Cache, 'getItem').mockReturnValue({ token: 'oidc_token' }); - - const spyon = jest.spyOn(RestClient.prototype, 'post').mockReturnValue(Promise.resolve({})); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, - apiKey = 'secret-api-key'; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: "API_KEY", - aws_appsync_apiKey: apiKey - }) - const GetEvent = `query GetEvent($id: ID! $nextToken: String) { + const doc = parse(GetEvent); + const query = print(doc); + + const headers = {}; + + const body = { + query, + variables, + }; + + const init = { + headers, + body, + signerServiceInfo: { + service: 'appsync', + region, + }, + }; + + await api.graphql({ + query: GetEvent, + variables, + authMode: GRAPHQL_AUTH_MODE.AWS_IAM, + }); + + expect(spyon).toBeCalledWith(url, init); + }); + test('multi-auth default case api-key, using OIDC as auth mode', async () => { + expect.assertions(1); + const cache_config = { + capacityInBytes: 3000, + itemMaxSize: 800, + defaultTTL: 3000000, + defaultPriority: 5, + warningThreshold: 0.8, + storage: window.localStorage, + }; + + Cache.configure(cache_config); + + jest.spyOn(Cache, 'getItem').mockReturnValue({ token: 'oidc_token' }); + + const spyon = jest + .spyOn(RestClient.prototype, 'post') + .mockReturnValue(Promise.resolve({})); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, + apiKey = 'secret-api-key'; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'API_KEY', + aws_appsync_apiKey: apiKey, + }); + const GetEvent = `query GetEvent($id: ID! $nextToken: String) { getEvent(id: $id) { id name @@ -444,59 +473,63 @@ describe('API test', () => { } }`; - const doc = parse(GetEvent); - const query = print(doc); - - const headers = { - Authorization: 'oidc_token' - }; - - const body = { - query, - variables, - }; - - const init = { - headers, - body, - signerServiceInfo: { - service: 'appsync', - region, - } - }; - - await api.graphql({ query: GetEvent, variables, authMode: GRAPHQL_AUTH_MODE.OPENID_CONNECT }); - - expect(spyon).toBeCalledWith(url, init); - }); - test('multi-auth using OIDC as auth mode, but no federatedSign', async () => { - expect.assertions(1); - - const cache_config = { - capacityInBytes: 3000, - itemMaxSize: 800, - defaultTTL: 3000000, - defaultPriority: 5, - warningThreshold: 0.8, - storage: window.localStorage - }; - - Cache.configure(cache_config); - - jest.spyOn(Cache, 'getItem').mockReturnValue(null); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, - apiKey = 'secret-api-key'; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: "API_KEY", - aws_appsync_apiKey: apiKey - }) - const GetEvent = `query GetEvent($id: ID! $nextToken: String) { + const doc = parse(GetEvent); + const query = print(doc); + + const headers = { + Authorization: 'oidc_token', + }; + + const body = { + query, + variables, + }; + + const init = { + headers, + body, + signerServiceInfo: { + service: 'appsync', + region, + }, + }; + + await api.graphql({ + query: GetEvent, + variables, + authMode: GRAPHQL_AUTH_MODE.OPENID_CONNECT, + }); + + expect(spyon).toBeCalledWith(url, init); + }); + test('multi-auth using OIDC as auth mode, but no federatedSign', async () => { + expect.assertions(1); + + const cache_config = { + capacityInBytes: 3000, + itemMaxSize: 800, + defaultTTL: 3000000, + defaultPriority: 5, + warningThreshold: 0.8, + storage: window.localStorage, + }; + + Cache.configure(cache_config); + + jest.spyOn(Cache, 'getItem').mockReturnValue(null); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, + apiKey = 'secret-api-key'; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'API_KEY', + aws_appsync_apiKey: apiKey, + }); + const GetEvent = `query GetEvent($id: ID! $nextToken: String) { getEvent(id: $id) { id name @@ -513,26 +546,29 @@ describe('API test', () => { } }`; - expect(api.graphql({ query: GetEvent, variables, authMode: GRAPHQL_AUTH_MODE.OPENID_CONNECT })) - .rejects.toThrowError("No federated jwt"); - - - }); - test('multi-auth using CUP as auth mode, but no userpool', async () => { - expect.assertions(1); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, - apiKey = 'secret-api-key'; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: "API_KEY", - aws_appsync_apiKey: apiKey - }) - const GetEvent = `query GetEvent($id: ID! $nextToken: String) { + expect( + api.graphql({ + query: GetEvent, + variables, + authMode: GRAPHQL_AUTH_MODE.OPENID_CONNECT, + }) + ).rejects.toThrowError('No federated jwt'); + }); + test('multi-auth using CUP as auth mode, but no userpool', async () => { + expect.assertions(1); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, + apiKey = 'secret-api-key'; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'API_KEY', + aws_appsync_apiKey: apiKey, + }); + const GetEvent = `query GetEvent($id: ID! $nextToken: String) { getEvent(id: $id) { id name @@ -549,36 +585,39 @@ describe('API test', () => { } }`; - expect(api.graphql({ query: GetEvent, variables, authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS })) - .rejects.toThrowError("No userPool"); - - }); - - test('multi-auth using API_KEY as auth mode, but no api-key configured', async () => { - expect.assertions(1); - - const cache_config = { - capacityInBytes: 3000, - itemMaxSize: 800, - defaultTTL: 3000000, - defaultPriority: 5, - warningThreshold: 0.8, - storage: window.localStorage - }; - - Cache.configure(cache_config); - - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: "AWS_IAM", - }) - const GetEvent = `query GetEvent($id: ID! $nextToken: String) { + expect( + api.graphql({ + query: GetEvent, + variables, + authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS, + }) + ).rejects.toThrowError('No userPool'); + }); + + test('multi-auth using API_KEY as auth mode, but no api-key configured', async () => { + expect.assertions(1); + + const cache_config = { + capacityInBytes: 3000, + itemMaxSize: 800, + defaultTTL: 3000000, + defaultPriority: 5, + warningThreshold: 0.8, + storage: window.localStorage, + }; + + Cache.configure(cache_config); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'AWS_IAM', + }); + const GetEvent = `query GetEvent($id: ID! $nextToken: String) { getEvent(id: $id) { id name @@ -595,29 +634,31 @@ describe('API test', () => { } }`; - - expect(api.graphql({ query: GetEvent, variables, authMode: GRAPHQL_AUTH_MODE.API_KEY })) - .rejects.toThrowError("No api-key configured"); - - - }); - test('multi-auth using AWS_IAM as auth mode, but no credentials', async () => { - expect.assertions(1); - - jest.spyOn(Credentials, 'get').mockReturnValue(Promise.reject()); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, - apiKey = 'secret-api-key'; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: "API_KEY", - aws_appsync_apiKey: apiKey - }) - const GetEvent = `query GetEvent($id: ID! $nextToken: String) { + expect( + api.graphql({ + query: GetEvent, + variables, + authMode: GRAPHQL_AUTH_MODE.API_KEY, + }) + ).rejects.toThrowError('No api-key configured'); + }); + test('multi-auth using AWS_IAM as auth mode, but no credentials', async () => { + expect.assertions(1); + + jest.spyOn(Credentials, 'get').mockReturnValue(Promise.reject()); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, + apiKey = 'secret-api-key'; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'API_KEY', + aws_appsync_apiKey: apiKey, + }); + const GetEvent = `query GetEvent($id: ID! $nextToken: String) { getEvent(id: $id) { id name @@ -634,32 +675,39 @@ describe('API test', () => { } }`; - expect(api.graphql({ query: GetEvent, variables, authMode: GRAPHQL_AUTH_MODE.AWS_IAM })) - .rejects.toThrowError("No credentials"); - }); - - test('multi-auth default case api-key, using CUP as auth mode', async () => { - expect.assertions(1); - const spyon = jest.spyOn(RestClient.prototype, 'post').mockReturnValue(Promise.resolve({})); - - jest.spyOn(Auth, 'currentSession').mockReturnValue({ - getAccessToken: () => ({ - getJwtToken: () => ("Secret-Token") - }) - }); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, - apiKey = 'secret-api-key'; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: "API_KEY", - aws_appsync_apiKey: apiKey - }) - const GetEvent = `query GetEvent($id: ID! $nextToken: String) { + expect( + api.graphql({ + query: GetEvent, + variables, + authMode: GRAPHQL_AUTH_MODE.AWS_IAM, + }) + ).rejects.toThrowError('No credentials'); + }); + + test('multi-auth default case api-key, using CUP as auth mode', async () => { + expect.assertions(1); + const spyon = jest + .spyOn(RestClient.prototype, 'post') + .mockReturnValue(Promise.resolve({})); + + jest.spyOn(Auth, 'currentSession').mockReturnValue({ + getAccessToken: () => ({ + getJwtToken: () => 'Secret-Token', + }), + }); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }, + apiKey = 'secret-api-key'; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'API_KEY', + aws_appsync_apiKey: apiKey, + }); + const GetEvent = `query GetEvent($id: ID! $nextToken: String) { getEvent(id: $id) { id name @@ -676,75 +724,80 @@ describe('API test', () => { } }`; - const doc = parse(GetEvent); - const query = print(doc); - - const headers = { - Authorization: 'Secret-Token' - }; - - const body = { - query, - variables, - }; - - const init = { - headers, - body, - signerServiceInfo: { - service: 'appsync', - region, - } - }; - - await api.graphql({ query: GetEvent, variables, authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS }); - - expect(spyon).toBeCalledWith(url, init); - }); - - test('authMode on subscription', async () => { - expect.assertions(1); - - jest.spyOn(RestClient.prototype, 'post') - .mockImplementation(async (url, init) => ({ - extensions: { - subscription: { - newSubscriptions: {} - } - } - })); - - const cache_config = { - capacityInBytes: 3000, - itemMaxSize: 800, - defaultTTL: 3000000, - defaultPriority: 5, - warningThreshold: 0.8, - storage: window.localStorage - }; - - Cache.configure(cache_config); - - jest.spyOn(Cache, 'getItem').mockReturnValue({ token: 'id_token' }); - - const spyon_Graphql = jest.spyOn(API.prototype, '_graphql'); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - apiKey = 'secret_api_key', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; - - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: 'API_KEY', - aws_appsync_apiKey: apiKey - }); - - PubSub.subscribe = jest.fn(() => Observable.of({})); - - const SubscribeToEventComments = `subscription SubscribeToEventComments($eventId: String!) { + const doc = parse(GetEvent); + const query = print(doc); + + const headers = { + Authorization: 'Secret-Token', + }; + + const body = { + query, + variables, + }; + + const init = { + headers, + body, + signerServiceInfo: { + service: 'appsync', + region, + }, + }; + + await api.graphql({ + query: GetEvent, + variables, + authMode: GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS, + }); + + expect(spyon).toBeCalledWith(url, init); + }); + + test('authMode on subscription', async () => { + expect.assertions(1); + + jest + .spyOn(RestClient.prototype, 'post') + .mockImplementation(async (url, init) => ({ + extensions: { + subscription: { + newSubscriptions: {}, + }, + }, + })); + + const cache_config = { + capacityInBytes: 3000, + itemMaxSize: 800, + defaultTTL: 3000000, + defaultPriority: 5, + warningThreshold: 0.8, + storage: window.localStorage, + }; + + Cache.configure(cache_config); + + jest.spyOn(Cache, 'getItem').mockReturnValue({ token: 'id_token' }); + + const spyon_Graphql = jest.spyOn(API.prototype, '_graphql'); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + apiKey = 'secret_api_key', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; + + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'API_KEY', + aws_appsync_apiKey: apiKey, + }); + + PubSub.subscribe = jest.fn(() => Observable.of({})); + + const SubscribeToEventComments = `subscription SubscribeToEventComments($eventId: String!) { subscribeToEventComments(eventId: $eventId) { eventId commentId @@ -752,43 +805,52 @@ describe('API test', () => { } }`; - const doc = parse(SubscribeToEventComments); - const query = print(doc); - - api.graphql({ query, variables, authMode: GRAPHQL_AUTH_MODE.OPENID_CONNECT }).subscribe(); - - expect(spyon_Graphql).toBeCalledWith(expect.objectContaining({ - authMode: "OPENID_CONNECT" - }), {}); - - }) - - test('happy-case-subscription', async (done) => { - jest.spyOn(RestClient.prototype, 'post') - .mockImplementation(async (url, init) => ({ - extensions: { - subscription: { - newSubscriptions: {} - } - } - })); - - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - apiKey = 'secret_api_key', - variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; - - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: 'API_KEY', - aws_appsync_apiKey: apiKey - }); - - PubSub.subscribe = jest.fn(() => Observable.of({})); - - const SubscribeToEventComments = `subscription SubscribeToEventComments($eventId: String!) { + const doc = parse(SubscribeToEventComments); + const query = print(doc); + + api + .graphql({ + query, + variables, + authMode: GRAPHQL_AUTH_MODE.OPENID_CONNECT, + }) + .subscribe(); + + expect(spyon_Graphql).toBeCalledWith( + expect.objectContaining({ + authMode: 'OPENID_CONNECT', + }), + {} + ); + }); + + test('happy-case-subscription', async done => { + jest + .spyOn(RestClient.prototype, 'post') + .mockImplementation(async (url, init) => ({ + extensions: { + subscription: { + newSubscriptions: {}, + }, + }, + })); + + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + apiKey = 'secret_api_key', + variables = { id: '809392da-ec91-4ef0-b219-5238a8f942b2' }; + + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'API_KEY', + aws_appsync_apiKey: apiKey, + }); + + PubSub.subscribe = jest.fn(() => Observable.of({})); + + const SubscribeToEventComments = `subscription SubscribeToEventComments($eventId: String!) { subscribeToEventComments(eventId: $eventId) { eventId commentId @@ -796,49 +858,57 @@ describe('API test', () => { } }`; - const doc = parse(SubscribeToEventComments); - const query = print(doc); - - const observable = api.graphql(graphqlOperation(query, variables)).subscribe({ - next: () => { - expect(PubSub.subscribe).toHaveBeenCalledTimes(1); - const subscribeOptions = PubSub.subscribe.mock.calls[0][1]; - expect(subscribeOptions.provider).toBe(INTERNAL_AWS_APPSYNC_PUBSUB_PROVIDER); - done(); - } - }); - - expect(observable).not.toBe(undefined); - }); - - test('happy case mutation', async () => { - const spyonAuth = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - - const spyon = jest.spyOn(RestClient.prototype, 'post').mockImplementationOnce((url, init) => { - return new Promise((res, rej) => { - res({}) - }); - }); - const api = new API(config); - const url = 'https://appsync.amazonaws.com', - region = 'us-east-2', - apiKey = 'secret_api_key', - variables = { - id: '809392da-ec91-4ef0-b219-5238a8f942b2', - content: 'lalala', - createdAt: new Date().toISOString() - }; - api.configure({ - aws_appsync_graphqlEndpoint: url, - aws_appsync_region: region, - aws_appsync_authenticationType: 'API_KEY', - aws_appsync_apiKey: apiKey - }) - const AddComment = `mutation AddComment($eventId: ID!, $content: String!, $createdAt: String!) { + const doc = parse(SubscribeToEventComments); + const query = print(doc); + + const observable = api + .graphql(graphqlOperation(query, variables)) + .subscribe({ + next: () => { + expect(PubSub.subscribe).toHaveBeenCalledTimes(1); + const subscribeOptions = PubSub.subscribe.mock.calls[0][1]; + expect(subscribeOptions.provider).toBe( + INTERNAL_AWS_APPSYNC_PUBSUB_PROVIDER + ); + done(); + }, + }); + + expect(observable).not.toBe(undefined); + }); + + test('happy case mutation', async () => { + const spyonAuth = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + + const spyon = jest + .spyOn(RestClient.prototype, 'post') + .mockImplementationOnce((url, init) => { + return new Promise((res, rej) => { + res({}); + }); + }); + const api = new API(config); + const url = 'https://appsync.amazonaws.com', + region = 'us-east-2', + apiKey = 'secret_api_key', + variables = { + id: '809392da-ec91-4ef0-b219-5238a8f942b2', + content: 'lalala', + createdAt: new Date().toISOString(), + }; + api.configure({ + aws_appsync_graphqlEndpoint: url, + aws_appsync_region: region, + aws_appsync_authenticationType: 'API_KEY', + aws_appsync_apiKey: apiKey, + }); + const AddComment = `mutation AddComment($eventId: ID!, $content: String!, $createdAt: String!) { commentOnEvent(eventId: $eventId, content: $content, createdAt: $createdAt) { eventId content @@ -846,862 +916,1031 @@ describe('API test', () => { } }`; - const doc = parse(AddComment); - const query = print(doc); - - const headers = { - Authorization: null, - 'X-Api-Key': apiKey - }; - - const body = { - query, - variables, - }; - - const init = { - headers, - body, - signerServiceInfo: { - service: 'appsync', - region, - } - }; - - await api.graphql(graphqlOperation(AddComment, variables)); - - expect(spyon).toBeCalledWith(url, init); - }); - }); - - describe('configure test', () => { - test('without aws_project_region', () => { - const api = new API({}); - - const options = { - myoption: 'myoption' - } - - expect(api.configure(options)).toEqual({ "endpoints": [], "myoption": "myoption" }); - }); - - test('with aws_project_region', () => { - const api = new API({}); - - const options = { - aws_project_region: 'region', - aws_cloud_logic_custom - } - - expect(api.configure(options)).toEqual({ - aws_cloud_logic_custom, - aws_project_region: 'region', - endpoints: aws_cloud_logic_custom, - header: {}, - region: 'region' - }); - }); - - test('with API options', () => { - const api = new API({}); - - const options = { - API: { - aws_project_region: 'api-region', - }, - aws_project_region: 'region', - aws_appsync_region: 'appsync-region', - aws_cloud_logic_custom - } - - expect(api.configure(options)).toEqual({ - aws_cloud_logic_custom, - aws_project_region: 'api-region', - aws_appsync_region: 'appsync-region', - endpoints: aws_cloud_logic_custom, - header: {}, - region: 'api-region' - }); - }); - }); - - - - describe('get test', () => { - test('happy case', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'get').mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - await api.get('apiName', 'path', 'init'); - - expect(spyon2).toBeCalledWith('endpointpath', 'init'); - - }); - - test('custom_header', async () => { - const custom_config = { - API: { - endpoints: [ - { - name: 'apiName', - endpoint: 'https://www.amazonaws.com', - custom_header: () => { return { Authorization: 'mytoken' } } - } - ] - } - }; - const api = new API({}); - api.configure(custom_config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - - const spyonRequest = jest.spyOn(RestClient.prototype, '_request').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res({}); - }); - }); - await api.get('apiName', 'path', {}); - - expect(spyonRequest).toBeCalledWith({ - "data": null, - "headers": {"Authorization": "mytoken"}, - "host": "www.amazonaws.compath", - "method": "GET", - "path": "/", - "responseType": "json", - "signerServiceInfo": undefined, - "url": "https://www.amazonaws.compath/", - "timeout": 0 - }, undefined); - - }); - - test('non-default timeout', async () => { - const resp = { data: [{ name: 'Bob' }] }; - - const options = { - aws_project_region: 'region', - aws_cloud_logic_custom - }; - - const api = new API(options); - const creds = { - secretAccessKey: 'secret', - accessKeyId: 'access', - sessionToken: 'token' - }; - - const creds2 = { - secret_key: 'secret', - access_key: 'access', - session_token: 'token' - }; - - const spyon = jest.spyOn(Credentials, 'get').mockImplementation(() => { - return new Promise((res, rej) => { - res(creds); - }); - }); - - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - const spyonSigner = jest.spyOn(Signer, 'sign').mockImplementationOnce(() => { - return { headers: {} }; - }); - - const spyAxios = jest.spyOn(axios, 'default').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(resp); - }); - }); - - const init = { - timeout: 2500 - } - await api.get('apiName', '/items', init); - const expectedParams = {"data": null, "headers": {}, "host": undefined, "method": "GET", "path": "/", "responseType": "json", "url": "endpoint/items", "timeout": 2500}; - expect(spyonSigner).toBeCalledWith( expectedParams, creds2 , { region: 'us-east-1', service: 'execute-api'}); - }); - - test('query-string on init', async () => { - const resp = { data: [{ name: 'Bob' }] }; - - const options = { - aws_project_region: 'region', - aws_cloud_logic_custom - }; - - const api = new API(options); - const creds = { - secretAccessKey: 'secret', - accessKeyId: 'access', - sessionToken: 'token' - }; - - const creds2 = { - secret_key: 'secret', - access_key: 'access', - session_token: 'token' - }; - - const spyon = jest.spyOn(Credentials, 'get').mockImplementation(() => { - return new Promise((res, rej) => { - res(creds); - }); - }); - - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - const spyonSigner = jest.spyOn(Signer, 'sign').mockImplementationOnce(() => { - return { headers: {} }; - }); - - const spyAxios = jest.spyOn(axios, 'default').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(resp); - }); - }); - - const init = { - queryStringParameters: { - 'ke:y3': 'val:ue 3' - } - } - await api.get('apiName', '/items', init); - const expectedParams = {"data": null, "headers": {}, "host": undefined, "method": "GET", "path": "/", "responseType": "json", "url": "endpoint/items?ke%3Ay3=val%3Aue%203", "timeout": 0}; - expect(spyonSigner).toBeCalledWith( expectedParams, creds2 , { region: 'us-east-1', service: 'execute-api'}); - }); - - test('query-string on init-custom-auth', async () => { - const resp = { data: [{ name: 'Bob' }] }; - - const options = { - aws_project_region: 'region', - aws_cloud_logic_custom - }; - - const api = new API(options); - const creds = { - secretAccessKey: 'secret', - accessKeyId: 'access', - sessionToken: 'token' - }; - - const creds2 = { - secret_key: 'secret', - access_key: 'access', - session_token: 'token' - }; - - const spyon = jest.spyOn(Credentials, 'get').mockImplementation(() => { - return new Promise((res, rej) => { - res(creds); - }); - }); - - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - const spyonRequest = jest.spyOn(RestClient.prototype, '_request').mockImplementationOnce(() => { - return { headers: {} }; - }); - - const spyAxios = jest.spyOn(axios, 'default').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(resp); - }); - }); - - const init = { - queryStringParameters: { - 'ke:y3': 'val:ue 3' - }, - headers: { - Authorization: 'apikey' - } - } - await api.get('apiName', '/items', init); - const expectedParams = {"data": null, "headers": {"Authorization": "apikey"}, "host": undefined, "method": "GET", "path": "/", "responseType": "json", "signerServiceInfo": undefined, "url": "endpoint/items?ke%3Ay3=val%3Aue%203", "timeout": 0}; - expect(spyonRequest).toBeCalledWith( expectedParams, undefined ); - }); - test('query-string on init and url', async () => { - const resp = { data: [{ name: 'Bob' }] }; - - const options = { - aws_project_region: 'region', - aws_cloud_logic_custom - }; - - const api = new API(options); - const creds = { - secretAccessKey: 'secret', - accessKeyId: 'access', - sessionToken: 'token' - }; - - const creds2 = { - secret_key: 'secret', - access_key: 'access', - session_token: 'token' - }; - - const spyon = jest.spyOn(Credentials, 'get').mockImplementation(() => { - return new Promise((res, rej) => { - res(creds); - }); - }); - - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - const spyonSigner = jest.spyOn(Signer, 'sign').mockImplementationOnce(() => { - return { headers: {} }; - }); - - const spyAxios = jest.spyOn(axios, 'default').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(resp); - }); - }); - - const init = { - queryStringParameters: { - 'key2': 'value2_real' - } - } - await api.get('apiName', '/items?key1=value1&key2=value', init); - const expectedParams = {"data": null, "headers": {}, "host": undefined, "method": "GET", "path": "/", "responseType": "json", "url": "endpoint/items?key1=value1&key2=value2_real", "timeout": 0}; - expect(spyonSigner).toBeCalledWith( expectedParams, creds2 , { region: 'us-east-1', service: 'execute-api'}); - }); - - test('endpoint length 0', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'get').mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return ''; - }); - - expect.assertions(1); - try { - await api.get('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('API apiName does not exist'); - } - - }); - - test('cred not ready', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err no current credentials'); - }); - }); - - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - const spyon4 = jest.spyOn(RestClient.prototype, '_request').mockImplementationOnce(() => { - return 'endpoint'; - }); - - expect.assertions(1); - await api.get('apiName', 'path', 'init'); - expect(spyon4).toBeCalled(); - }); - - test('no restclient instance', async () => { - const api = new API(config); - const spyon = jest.spyOn(API.prototype, 'createInstance').mockImplementationOnce(() => { - return Promise.reject('err'); - }); - - expect.assertions(1); - try { - await api.get('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('err'); - } - - }); - }); - - describe('post test', () => { - - test('happy case', async () => { - const api = new API({ - region: 'region-2', - }); - const options = { - aws_project_region: 'region', - aws_cloud_logic_custom - }; - - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'post').mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - api.configure(options); - await api.post('apiName', 'path', 'init'); - - expect(spyon2).toBeCalledWith('endpointpath', 'init'); - - }); - - test.skip('endpoint length 0', async () => { - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'post').mockImplementationOnce(() => { - - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return ''; - }); - - const api = new API(config); - expect.assertions(1); - try { - await api.post('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('API apiName does not exist'); - } - - }); - - test('cred not ready', async () => { - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - const api = new API(config); - const spyon4 = jest.spyOn(RestClient.prototype, '_request').mockImplementationOnce(() => { - return 'endpoint'; - }); - - expect.assertions(1); - await api.post('apiName', 'path', 'init'); - expect(spyon4).toBeCalled(); - - }); - - test('no restclient instance', async () => { - const api = new API(config); - const spyon = jest.spyOn(API.prototype, 'createInstance').mockImplementationOnce(() => { - return Promise.reject('err'); - }); - - expect.assertions(1); - try { - await api.post('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('err'); - } - - }); - }); - - describe('put test', () => { - test('happy case', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'put').mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - await api.put('apiName', 'path', 'init'); - - expect(spyon2).toBeCalledWith('endpointpath', 'init'); - - }); - - test.skip('endpoint length 0', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'put').mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return ''; - }); - - expect.assertions(1); - try { - await api.put('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('API apiName does not exist'); - } - - }); - - test('cred not ready', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - const spyon4 = jest.spyOn(RestClient.prototype, '_request').mockImplementationOnce(() => { - return 'endpoint'; - }); - - expect.assertions(1); - await api.put('apiName', 'path', 'init'); - expect(spyon4).toBeCalled(); - - }); - - test('no restclient instance', async () => { - const api = new API(config); - const spyon = jest.spyOn(API.prototype, 'createInstance').mockImplementationOnce(() => { - return Promise.reject('err'); - }); - - expect.assertions(1); - try { - await api.put('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('err'); - } - - }); - }); - - describe('patch test', () => { - test('happy case', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'patch').mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - await api.patch('apiName', 'path', 'init'); - - expect(spyon2).toBeCalledWith('endpointpath', 'init'); - - - }); - - test.skip('endpoint length 0', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'patch').mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return ''; - }); - - expect.assertions(1); - try { - await api.patch('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('API apiName does not exist'); - } - - }); - - test('cred not ready', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - const spyon4 = jest.spyOn(RestClient.prototype, '_request').mockImplementationOnce(() => { - return 'endpoint'; - }); - - expect.assertions(1); - await api.patch('apiName', 'path', 'init'); - expect(spyon4).toBeCalled(); - - }); - - test('no restclient instance', async () => { - const api = new API(config); - const spyon = jest.spyOn(API.prototype, 'createInstance').mockImplementationOnce(() => { - return Promise.reject('err'); - }); - - expect.assertions(1); - try { - await api.patch('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('err'); - } - - }); - }); - - describe('del test', () => { - test('happy case', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'del').mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - await api.del('apiName', 'path', 'init'); - - expect(spyon2).toBeCalledWith('endpointpath', 'init'); - - - }); - - test.skip('endpoint length 0', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'del').mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return ''; - }); - - expect.assertions(1); - try { - await api.del('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('API apiName does not exist'); - } - - }); - - test('cred not ready', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - const spyon4 = jest.spyOn(RestClient.prototype, '_request').mockImplementationOnce(() => { - return 'endpoint'; - }); - - expect.assertions(1); - await api.del('apiName', 'path', 'init'); - expect(spyon4).toBeCalled(); - - }); - - test('no restclient instance', async () => { - const api = new API(config); - const spyon = jest.spyOn(API.prototype, 'createInstance').mockImplementationOnce(() => { - return Promise.reject('err'); - }); - - expect.assertions(1); - try { - await api.del('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('err'); - } - - }); - }); - - describe('head test', () => { - test('happy case', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'head').mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - await api.head('apiName', 'path', 'init'); - - expect(spyon2).toBeCalledWith('endpointpath', 'init'); - - }); - - test.skip('endpoint length 0', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('cred'); - }); - }); - const spyon2 = jest.spyOn(RestClient.prototype, 'head').mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return ''; - }); - - expect.assertions(1); - try { - await api.head('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('API apiName does not exist'); - } - - }); - - test('cred not ready', async () => { - const api = new API(config); - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - const spyon3 = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - const spyon4 = jest.spyOn(RestClient.prototype, '_request').mockImplementationOnce(() => { - return 'endpoint'; - }); - - expect.assertions(1); - await api.head('apiName', 'path', 'init'); - expect(spyon4).toBeCalled(); - - }); - - test('no restclient instance', async () => { - const api = new API(config); - const spyon = jest.spyOn(API.prototype, 'createInstance').mockImplementationOnce(() => { - return Promise.reject('err'); - }); - - expect.assertions(1); - try { - await api.head('apiName', 'path', 'init'); - } catch (e) { - expect(e).toBe('err'); - } - - }); - }); - - describe('endpoint test', () => { - test('happy case', async () => { - const api = new API(config); - const spyon = jest.spyOn(RestClient.prototype, 'endpoint').mockImplementationOnce(() => { - return 'endpoint'; - }); - - await api.endpoint('apiName'); - - expect(spyon).toBeCalledWith('apiName'); - - }); - - test('no restclient instance', async () => { - const api = new API(config); - const spyon = jest.spyOn(API.prototype, 'createInstance').mockImplementationOnce(() => { - return Promise.reject('err'); - }); - - expect.assertions(1); - try { - await api.endpoint('apiName'); - } catch (e) { - expect(e).toBe('err'); - } - - }); - }); - - - + const doc = parse(AddComment); + const query = print(doc); + + const headers = { + Authorization: null, + 'X-Api-Key': apiKey, + }; + + const body = { + query, + variables, + }; + + const init = { + headers, + body, + signerServiceInfo: { + service: 'appsync', + region, + }, + }; + + await api.graphql(graphqlOperation(AddComment, variables)); + + expect(spyon).toBeCalledWith(url, init); + }); + }); + + describe('configure test', () => { + test('without aws_project_region', () => { + const api = new API({}); + + const options = { + myoption: 'myoption', + }; + + expect(api.configure(options)).toEqual({ + endpoints: [], + myoption: 'myoption', + }); + }); + + test('with aws_project_region', () => { + const api = new API({}); + + const options = { + aws_project_region: 'region', + aws_cloud_logic_custom, + }; + + expect(api.configure(options)).toEqual({ + aws_cloud_logic_custom, + aws_project_region: 'region', + endpoints: aws_cloud_logic_custom, + header: {}, + region: 'region', + }); + }); + + test('with API options', () => { + const api = new API({}); + + const options = { + API: { + aws_project_region: 'api-region', + }, + aws_project_region: 'region', + aws_appsync_region: 'appsync-region', + aws_cloud_logic_custom, + }; + + expect(api.configure(options)).toEqual({ + aws_cloud_logic_custom, + aws_project_region: 'api-region', + aws_appsync_region: 'appsync-region', + endpoints: aws_cloud_logic_custom, + header: {}, + region: 'api-region', + }); + }); + }); + + describe('get test', () => { + test('happy case', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'get') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + await api.get('apiName', 'path', 'init'); + + expect(spyon2).toBeCalledWith('endpointpath', 'init'); + }); + + test('custom_header', async () => { + const custom_config = { + API: { + endpoints: [ + { + name: 'apiName', + endpoint: 'https://www.amazonaws.com', + custom_header: () => { + return { Authorization: 'mytoken' }; + }, + }, + ], + }, + }; + const api = new API({}); + api.configure(custom_config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + + const spyonRequest = jest + .spyOn(RestClient.prototype, '_request') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res({}); + }); + }); + await api.get('apiName', 'path', {}); + + expect(spyonRequest).toBeCalledWith( + { + data: null, + headers: { Authorization: 'mytoken' }, + host: 'www.amazonaws.compath', + method: 'GET', + path: '/', + responseType: 'json', + signerServiceInfo: undefined, + url: 'https://www.amazonaws.compath/', + timeout: 0, + }, + undefined + ); + }); + + test('non-default timeout', async () => { + const resp = { data: [{ name: 'Bob' }] }; + + const options = { + aws_project_region: 'region', + aws_cloud_logic_custom, + }; + + const api = new API(options); + const creds = { + secretAccessKey: 'secret', + accessKeyId: 'access', + sessionToken: 'token', + }; + + const creds2 = { + secret_key: 'secret', + access_key: 'access', + session_token: 'token', + }; + + const spyon = jest.spyOn(Credentials, 'get').mockImplementation(() => { + return new Promise((res, rej) => { + res(creds); + }); + }); + + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + const spyonSigner = jest + .spyOn(Signer, 'sign') + .mockImplementationOnce(() => { + return { headers: {} }; + }); + + const spyAxios = jest + .spyOn(axios, 'default') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(resp); + }); + }); + + const init = { + timeout: 2500, + }; + await api.get('apiName', '/items', init); + const expectedParams = { + data: null, + headers: {}, + host: undefined, + method: 'GET', + path: '/', + responseType: 'json', + url: 'endpoint/items', + timeout: 2500, + }; + expect(spyonSigner).toBeCalledWith(expectedParams, creds2, { + region: 'us-east-1', + service: 'execute-api', + }); + }); + + test('query-string on init', async () => { + const resp = { data: [{ name: 'Bob' }] }; + + const options = { + aws_project_region: 'region', + aws_cloud_logic_custom, + }; + + const api = new API(options); + const creds = { + secretAccessKey: 'secret', + accessKeyId: 'access', + sessionToken: 'token', + }; + + const creds2 = { + secret_key: 'secret', + access_key: 'access', + session_token: 'token', + }; + + const spyon = jest.spyOn(Credentials, 'get').mockImplementation(() => { + return new Promise((res, rej) => { + res(creds); + }); + }); + + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + const spyonSigner = jest + .spyOn(Signer, 'sign') + .mockImplementationOnce(() => { + return { headers: {} }; + }); + + const spyAxios = jest + .spyOn(axios, 'default') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(resp); + }); + }); + + const init = { + queryStringParameters: { + 'ke:y3': 'val:ue 3', + }, + }; + await api.get('apiName', '/items', init); + const expectedParams = { + data: null, + headers: {}, + host: undefined, + method: 'GET', + path: '/', + responseType: 'json', + url: 'endpoint/items?ke%3Ay3=val%3Aue%203', + timeout: 0, + }; + expect(spyonSigner).toBeCalledWith(expectedParams, creds2, { + region: 'us-east-1', + service: 'execute-api', + }); + }); + + test('query-string on init-custom-auth', async () => { + const resp = { data: [{ name: 'Bob' }] }; + + const options = { + aws_project_region: 'region', + aws_cloud_logic_custom, + }; + + const api = new API(options); + const creds = { + secretAccessKey: 'secret', + accessKeyId: 'access', + sessionToken: 'token', + }; + + const creds2 = { + secret_key: 'secret', + access_key: 'access', + session_token: 'token', + }; + + const spyon = jest.spyOn(Credentials, 'get').mockImplementation(() => { + return new Promise((res, rej) => { + res(creds); + }); + }); + + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + const spyonRequest = jest + .spyOn(RestClient.prototype, '_request') + .mockImplementationOnce(() => { + return { headers: {} }; + }); + + const spyAxios = jest + .spyOn(axios, 'default') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(resp); + }); + }); + + const init = { + queryStringParameters: { + 'ke:y3': 'val:ue 3', + }, + headers: { + Authorization: 'apikey', + }, + }; + await api.get('apiName', '/items', init); + const expectedParams = { + data: null, + headers: { Authorization: 'apikey' }, + host: undefined, + method: 'GET', + path: '/', + responseType: 'json', + signerServiceInfo: undefined, + url: 'endpoint/items?ke%3Ay3=val%3Aue%203', + timeout: 0, + }; + expect(spyonRequest).toBeCalledWith(expectedParams, undefined); + }); + test('query-string on init and url', async () => { + const resp = { data: [{ name: 'Bob' }] }; + + const options = { + aws_project_region: 'region', + aws_cloud_logic_custom, + }; + + const api = new API(options); + const creds = { + secretAccessKey: 'secret', + accessKeyId: 'access', + sessionToken: 'token', + }; + + const creds2 = { + secret_key: 'secret', + access_key: 'access', + session_token: 'token', + }; + + const spyon = jest.spyOn(Credentials, 'get').mockImplementation(() => { + return new Promise((res, rej) => { + res(creds); + }); + }); + + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + const spyonSigner = jest + .spyOn(Signer, 'sign') + .mockImplementationOnce(() => { + return { headers: {} }; + }); + + const spyAxios = jest + .spyOn(axios, 'default') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(resp); + }); + }); + + const init = { + queryStringParameters: { + key2: 'value2_real', + }, + }; + await api.get('apiName', '/items?key1=value1&key2=value', init); + const expectedParams = { + data: null, + headers: {}, + host: undefined, + method: 'GET', + path: '/', + responseType: 'json', + url: 'endpoint/items?key1=value1&key2=value2_real', + timeout: 0, + }; + expect(spyonSigner).toBeCalledWith(expectedParams, creds2, { + region: 'us-east-1', + service: 'execute-api', + }); + }); + + test('endpoint length 0', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'get') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return ''; + }); + + expect.assertions(1); + try { + await api.get('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('API apiName does not exist'); + } + }); + + test('cred not ready', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err no current credentials'); + }); + }); + + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + const spyon4 = jest + .spyOn(RestClient.prototype, '_request') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + expect.assertions(1); + await api.get('apiName', 'path', 'init'); + expect(spyon4).toBeCalled(); + }); + + test('no restclient instance', async () => { + const api = new API(config); + const spyon = jest + .spyOn(API.prototype, 'createInstance') + .mockImplementationOnce(() => { + return Promise.reject('err'); + }); + + expect.assertions(1); + try { + await api.get('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('err'); + } + }); + }); + + describe('post test', () => { + test('happy case', async () => { + const api = new API({ + region: 'region-2', + }); + const options = { + aws_project_region: 'region', + aws_cloud_logic_custom, + }; + + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'post') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + api.configure(options); + await api.post('apiName', 'path', 'init'); + + expect(spyon2).toBeCalledWith('endpointpath', 'init'); + }); + + test.skip('endpoint length 0', async () => { + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'post') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return ''; + }); + + const api = new API(config); + expect.assertions(1); + try { + await api.post('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('API apiName does not exist'); + } + }); + + test('cred not ready', async () => { + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + const api = new API(config); + const spyon4 = jest + .spyOn(RestClient.prototype, '_request') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + expect.assertions(1); + await api.post('apiName', 'path', 'init'); + expect(spyon4).toBeCalled(); + }); + + test('no restclient instance', async () => { + const api = new API(config); + const spyon = jest + .spyOn(API.prototype, 'createInstance') + .mockImplementationOnce(() => { + return Promise.reject('err'); + }); + + expect.assertions(1); + try { + await api.post('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('err'); + } + }); + }); + + describe('put test', () => { + test('happy case', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'put') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + await api.put('apiName', 'path', 'init'); + + expect(spyon2).toBeCalledWith('endpointpath', 'init'); + }); + + test.skip('endpoint length 0', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'put') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return ''; + }); + + expect.assertions(1); + try { + await api.put('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('API apiName does not exist'); + } + }); + + test('cred not ready', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + const spyon4 = jest + .spyOn(RestClient.prototype, '_request') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + expect.assertions(1); + await api.put('apiName', 'path', 'init'); + expect(spyon4).toBeCalled(); + }); + + test('no restclient instance', async () => { + const api = new API(config); + const spyon = jest + .spyOn(API.prototype, 'createInstance') + .mockImplementationOnce(() => { + return Promise.reject('err'); + }); + + expect.assertions(1); + try { + await api.put('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('err'); + } + }); + }); + + describe('patch test', () => { + test('happy case', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'patch') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + await api.patch('apiName', 'path', 'init'); + + expect(spyon2).toBeCalledWith('endpointpath', 'init'); + }); + + test.skip('endpoint length 0', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'patch') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return ''; + }); + + expect.assertions(1); + try { + await api.patch('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('API apiName does not exist'); + } + }); + + test('cred not ready', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + const spyon4 = jest + .spyOn(RestClient.prototype, '_request') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + expect.assertions(1); + await api.patch('apiName', 'path', 'init'); + expect(spyon4).toBeCalled(); + }); + + test('no restclient instance', async () => { + const api = new API(config); + const spyon = jest + .spyOn(API.prototype, 'createInstance') + .mockImplementationOnce(() => { + return Promise.reject('err'); + }); + + expect.assertions(1); + try { + await api.patch('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('err'); + } + }); + }); + + describe('del test', () => { + test('happy case', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'del') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + await api.del('apiName', 'path', 'init'); + + expect(spyon2).toBeCalledWith('endpointpath', 'init'); + }); + + test.skip('endpoint length 0', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'del') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return ''; + }); + + expect.assertions(1); + try { + await api.del('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('API apiName does not exist'); + } + }); + + test('cred not ready', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + const spyon4 = jest + .spyOn(RestClient.prototype, '_request') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + expect.assertions(1); + await api.del('apiName', 'path', 'init'); + expect(spyon4).toBeCalled(); + }); + + test('no restclient instance', async () => { + const api = new API(config); + const spyon = jest + .spyOn(API.prototype, 'createInstance') + .mockImplementationOnce(() => { + return Promise.reject('err'); + }); + + expect.assertions(1); + try { + await api.del('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('err'); + } + }); + }); + + describe('head test', () => { + test('happy case', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'head') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + await api.head('apiName', 'path', 'init'); + + expect(spyon2).toBeCalledWith('endpointpath', 'init'); + }); + + test.skip('endpoint length 0', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('cred'); + }); + }); + const spyon2 = jest + .spyOn(RestClient.prototype, 'head') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return ''; + }); + + expect.assertions(1); + try { + await api.head('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('API apiName does not exist'); + } + }); + + test('cred not ready', async () => { + const api = new API(config); + const spyon = jest + .spyOn(Credentials, 'get') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + const spyon3 = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + const spyon4 = jest + .spyOn(RestClient.prototype, '_request') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + expect.assertions(1); + await api.head('apiName', 'path', 'init'); + expect(spyon4).toBeCalled(); + }); + + test('no restclient instance', async () => { + const api = new API(config); + const spyon = jest + .spyOn(API.prototype, 'createInstance') + .mockImplementationOnce(() => { + return Promise.reject('err'); + }); + + expect.assertions(1); + try { + await api.head('apiName', 'path', 'init'); + } catch (e) { + expect(e).toBe('err'); + } + }); + }); + + describe('endpoint test', () => { + test('happy case', async () => { + const api = new API(config); + const spyon = jest + .spyOn(RestClient.prototype, 'endpoint') + .mockImplementationOnce(() => { + return 'endpoint'; + }); + + await api.endpoint('apiName'); + + expect(spyon).toBeCalledWith('apiName'); + }); + + test('no restclient instance', async () => { + const api = new API(config); + const spyon = jest + .spyOn(API.prototype, 'createInstance') + .mockImplementationOnce(() => { + return Promise.reject('err'); + }); + + expect.assertions(1); + try { + await api.endpoint('apiName'); + } catch (e) { + expect(e).toBe('err'); + } + }); + }); }); - - diff --git a/packages/api/src/API.ts b/packages/api/src/API.ts index cd286855213..38a98e56277 100644 --- a/packages/api/src/API.ts +++ b/packages/api/src/API.ts @@ -15,7 +15,10 @@ import { print } from 'graphql/language/printer'; import { parse } from 'graphql/language/parser'; import * as Observable from 'zen-observable'; import { RestClient as RestClass } from './RestClient'; -import Amplify, { ConsoleLogger as Logger, Credentials } from '@aws-amplify/core'; +import Amplify, { + ConsoleLogger as Logger, + Credentials, +} from '@aws-amplify/core'; import Auth from '@aws-amplify/auth'; import { GraphQLOptions, GraphQLResult } from './types'; import Cache from '@aws-amplify/cache'; @@ -24,478 +27,510 @@ import { v4 as uuid } from 'uuid'; const logger = new Logger('API'); -export const graphqlOperation = (query, variables = {}) => ({ query, variables }); +export const graphqlOperation = (query, variables = {}) => ({ + query, + variables, +}); /** * Export Cloud Logic APIs */ export default class APIClass { - /** - * @private - */ - private _options; - private _api = null; - private _pubSub = Amplify.PubSub; - - /** - * Initialize Storage with AWS configuration - * @param {Object} options - Configuration object for storage - */ - constructor(options) { - this._options = options; - logger.debug('API Options', this._options); - } - - public getModuleName() { - return 'API'; - } - - /** - * Configure API part with aws configurations - * @param {Object} config - Configuration of the API - * @return {Object} - The current configuration - */ - configure(options) { - const { API = {}, ...otherOptions } = options || {}; - let opt = { ...otherOptions, ...API }; - logger.debug('configure API', { opt }); - - if (opt['aws_project_region']) { - if (opt['aws_cloud_logic_custom']) { - const custom = opt['aws_cloud_logic_custom']; - opt.endpoints = (typeof custom === 'string') ? JSON.parse(custom) - : custom; - } - - opt = Object.assign({}, opt, { - region: opt['aws_project_region'], - header: {}, - }); - } - - if (!Array.isArray(opt.endpoints)) { - opt.endpoints = []; - } - - // Check if endpoints has custom_headers and validate if is a function - opt.endpoints.forEach((endpoint) => { - if (typeof endpoint.custom_header !== 'undefined' && typeof endpoint.custom_header !== 'function') { - logger.warn('API ' + endpoint.name + ', custom_header should be a function'); - endpoint.custom_header = undefined; - } - }); - - if (typeof opt.graphql_headers !== 'undefined' && typeof opt.graphql_headers !== 'function') { - logger.warn('graphql_headers should be a function'); - opt.graphql_headers = undefined; - } - - this._options = Object.assign({}, this._options, opt); - - this.createInstance(); - - return this._options; - } - - /** - * Create an instance of API for the library - * @return - A promise of true if Success - */ - createInstance() { - logger.debug('create API instance'); - if (this._options) { - this._api = new RestClass(this._options); - return true; - } else { - return Promise.reject('API not configured'); - } - } - - /** - * Make a GET request - * @param {string} apiName - The api name of the request - * @param {string} path - The path of the request - * @param {json} [init] - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - async get(apiName, path, init) { - if (!this._api) { - try { - await this.createInstance(); - } catch (error) { - return Promise.reject(error); - } - } - - const endpoint = this._api.endpoint(apiName); - if (endpoint.length === 0) { - return Promise.reject('API ' + apiName + ' does not exist'); - } - return this._api.get(endpoint + path, init); - } - - /** - * Make a POST request - * @param {string} apiName - The api name of the request - * @param {string} path - The path of the request - * @param {json} [init] - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - async post(apiName, path, init) { - if (!this._api) { - try { - await this.createInstance(); - } catch (error) { - return Promise.reject(error); - } - } - - const endpoint = this._api.endpoint(apiName); - if (endpoint.length === 0) { - return Promise.reject('API ' + apiName + ' does not exist'); - } - return this._api.post(endpoint + path, init); - } - - /** - * Make a PUT request - * @param {string} apiName - The api name of the request - * @param {string} path - The path of the request - * @param {json} [init] - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - async put(apiName, path, init) { - if (!this._api) { - try { - await this.createInstance(); - } catch (error) { - return Promise.reject(error); - } - } - - const endpoint = this._api.endpoint(apiName); - if (endpoint.length === 0) { - return Promise.reject('API ' + apiName + ' does not exist'); - } - return this._api.put(endpoint + path, init); - } - - /** - * Make a PATCH request - * @param {string} apiName - The api name of the request - * @param {string} path - The path of the request - * @param {json} [init] - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - async patch(apiName, path, init) { - if (!this._api) { - try { - await this.createInstance(); - } catch (error) { - return Promise.reject(error); - } - } - - const endpoint = this._api.endpoint(apiName); - if (endpoint.length === 0) { - return Promise.reject('API ' + apiName + ' does not exist'); - } - return this._api.patch(endpoint + path, init); - } - - /** - * Make a DEL request - * @param {string} apiName - The api name of the request - * @param {string} path - The path of the request - * @param {json} [init] - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - async del(apiName, path, init) { - if (!this._api) { - try { - await this.createInstance(); - } catch (error) { - return Promise.reject(error); - } - } - - const endpoint = this._api.endpoint(apiName); - if (endpoint.length === 0) { - return Promise.reject('API ' + apiName + ' does not exist'); - } - return this._api.del(endpoint + path, init); - } - - /** - * Make a HEAD request - * @param {string} apiName - The api name of the request - * @param {string} path - The path of the request - * @param {json} [init] - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - async head(apiName, path, init) { - if (!this._api) { - try { - await this.createInstance(); - } catch (error) { - return Promise.reject(error); - } - } - - const endpoint = this._api.endpoint(apiName); - if (endpoint.length === 0) { - return Promise.reject('API ' + apiName + ' does not exist'); - } - return this._api.head(endpoint + path, init); - } - - /** - * Getting endpoint for API - * @param {string} apiName - The name of the api - * @return {string} - The endpoint of the api - */ - async endpoint(apiName) { - if (!this._api) { - try { - await this.createInstance(); - } catch (error) { - return Promise.reject(error); - } - } - return this._api.endpoint(apiName); - } - - private async _headerBasedAuth(defaultAuthenticationType?) { - const { - aws_appsync_authenticationType, - aws_appsync_apiKey: apiKey, - } = this._options; - const authenticationType = defaultAuthenticationType || aws_appsync_authenticationType || "AWS_IAM"; - let headers = {}; - - switch (authenticationType) { - case 'API_KEY': - if (!apiKey) { - throw new Error('No api-key configured'); - } - headers = { - Authorization: null, - 'X-Api-Key': apiKey - }; - break; - case 'AWS_IAM': - const credentialsOK = await this._ensureCredentials(); - if (!credentialsOK) { throw new Error('No credentials'); } - break; - case 'OPENID_CONNECT': - const federatedInfo = await Cache.getItem('federatedInfo'); - - if (!federatedInfo || !federatedInfo.token) { throw new Error('No federated jwt'); } - headers = { - Authorization: federatedInfo.token - }; - break; - case 'AMAZON_COGNITO_USER_POOLS': - const session = await Auth.currentSession(); - headers = { - Authorization: session.getAccessToken().getJwtToken() - }; - break; - default: - headers = { - Authorization: null, - }; - break; - } - - return headers; - } - - /** - * to get the operation type - * @param operation - */ - getGraphqlOperationType(operation) { - const doc = parse(operation); - const { definitions: [{ operation: operationType },] } = doc; - - return operationType; - } - - /** - * Executes a GraphQL operation - * - * @param {GraphQLOptions} GraphQL Options - * @returns {Promise | Observable} - */ - graphql({ query: paramQuery, variables = {}, authMode }: GraphQLOptions) { - - const query = typeof paramQuery === 'string' ? parse(paramQuery) : parse(print(paramQuery)); - - const [operationDef = {},] = query.definitions.filter(def => def.kind === 'OperationDefinition'); - const { operation: operationType } = operationDef as OperationDefinitionNode; - - switch (operationType) { - case 'query': - case 'mutation': - return this._graphql({ query, variables, authMode }); - case 'subscription': - return this._graphqlSubscribe({ query, variables, authMode }); - } - - throw new Error(`invalid operation type: ${operationType}`); - } - - private async _graphql({ query, variables, authMode }: GraphQLOptions, additionalHeaders = {}) - : Promise { - if (!this._api) { - await this.createInstance(); - } - - const { - aws_appsync_region: region, - aws_appsync_graphqlEndpoint: appSyncGraphqlEndpoint, - graphql_headers = () => ({}), - graphql_endpoint: customGraphqlEndpoint, - graphql_endpoint_iam_region: customEndpointRegion - } = this._options; - - const headers = { - ...(!customGraphqlEndpoint && await this._headerBasedAuth(authMode)), - ...(customGraphqlEndpoint && - (customEndpointRegion ? await this._headerBasedAuth(authMode) : { Authorization: null }) - ), - ...additionalHeaders, - ... await graphql_headers({ query, variables }), - }; - - const body = { - query: print(query), - variables, - }; - - const init = { - headers, - body, - signerServiceInfo: { - service: !customGraphqlEndpoint ? 'appsync' : 'execute-api', - region: !customGraphqlEndpoint ? region : customEndpointRegion - } - }; - - const endpoint = customGraphqlEndpoint || appSyncGraphqlEndpoint; - - if (!endpoint) { - const error = new GraphQLError('No graphql endpoint provided.'); - - throw { - data: {}, - errors: [error], - }; - } - - let response; - try { - response = await this._api.post(endpoint, init); - } catch (err) { - response = { - data: {}, - errors: [ - new GraphQLError(err.message) - ] - }; - } - - const { errors } = response; - - if (errors && errors.length) { - throw response; - } - - return response; - } - - private clientIdentifier = uuid(); - - private _graphqlSubscribe({ query, variables, authMode }: GraphQLOptions): Observable { - if (Amplify.PubSub && typeof Amplify.PubSub.subscribe === 'function') { - return new Observable(observer => { - - let handle = null; - - (async () => { - const { - aws_appsync_authenticationType, - } = this._options; - const authenticationType = authMode || aws_appsync_authenticationType; - const additionalheaders = { - ...(authenticationType === 'API_KEY' ? { - 'x-amz-subscriber-id': this.clientIdentifier - } : {}) - }; - - try { - const { - extensions: { subscription }, - - } = await this._graphql({ query, variables, authMode }, additionalheaders); - - const { newSubscriptions } = subscription; - - const newTopics = - Object.getOwnPropertyNames(newSubscriptions).map(p => newSubscriptions[p].topic); - - const observable = Amplify.PubSub.subscribe(newTopics, { - ...subscription, - provider: INTERNAL_AWS_APPSYNC_PUBSUB_PROVIDER, - }); - - handle = observable.subscribe({ - next: (data) => observer.next(data), - complete: () => observer.complete(), - error: (data) => { - const error = { ...data }; - if (!error.errors) { - error.errors = [{ - ...new GraphQLError('Network Error') - }]; - } - observer.error(error); - } - }); - - } catch (error) { - observer.error(error); - } - })(); - - return () => { - if (handle) { - handle.unsubscribe(); - } - }; - }); - } else { - logger.debug('No pubsub module applied for subscription'); - throw new Error('No pubsub module applied for subscription'); - } - } - - /** - * @private - */ - _ensureCredentials() { - return Credentials.get() - .then(credentials => { - if (!credentials) return false; - const cred = Credentials.shear(credentials); - logger.debug('set credentials for api', cred); - - return true; - }) - .catch(err => { - logger.warn('ensure credentials error', err); - return false; - }); - } + /** + * @private + */ + private _options; + private _api = null; + private _pubSub = Amplify.PubSub; + + /** + * Initialize Storage with AWS configuration + * @param {Object} options - Configuration object for storage + */ + constructor(options) { + this._options = options; + logger.debug('API Options', this._options); + } + + public getModuleName() { + return 'API'; + } + + /** + * Configure API part with aws configurations + * @param {Object} config - Configuration of the API + * @return {Object} - The current configuration + */ + configure(options) { + const { API = {}, ...otherOptions } = options || {}; + let opt = { ...otherOptions, ...API }; + logger.debug('configure API', { opt }); + + if (opt['aws_project_region']) { + if (opt['aws_cloud_logic_custom']) { + const custom = opt['aws_cloud_logic_custom']; + opt.endpoints = + typeof custom === 'string' ? JSON.parse(custom) : custom; + } + + opt = Object.assign({}, opt, { + region: opt['aws_project_region'], + header: {}, + }); + } + + if (!Array.isArray(opt.endpoints)) { + opt.endpoints = []; + } + + // Check if endpoints has custom_headers and validate if is a function + opt.endpoints.forEach(endpoint => { + if ( + typeof endpoint.custom_header !== 'undefined' && + typeof endpoint.custom_header !== 'function' + ) { + logger.warn( + 'API ' + endpoint.name + ', custom_header should be a function' + ); + endpoint.custom_header = undefined; + } + }); + + if ( + typeof opt.graphql_headers !== 'undefined' && + typeof opt.graphql_headers !== 'function' + ) { + logger.warn('graphql_headers should be a function'); + opt.graphql_headers = undefined; + } + + this._options = Object.assign({}, this._options, opt); + + this.createInstance(); + + return this._options; + } + + /** + * Create an instance of API for the library + * @return - A promise of true if Success + */ + createInstance() { + logger.debug('create API instance'); + if (this._options) { + this._api = new RestClass(this._options); + return true; + } else { + return Promise.reject('API not configured'); + } + } + + /** + * Make a GET request + * @param {string} apiName - The api name of the request + * @param {string} path - The path of the request + * @param {json} [init] - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + async get(apiName, path, init) { + if (!this._api) { + try { + await this.createInstance(); + } catch (error) { + return Promise.reject(error); + } + } + + const endpoint = this._api.endpoint(apiName); + if (endpoint.length === 0) { + return Promise.reject('API ' + apiName + ' does not exist'); + } + return this._api.get(endpoint + path, init); + } + + /** + * Make a POST request + * @param {string} apiName - The api name of the request + * @param {string} path - The path of the request + * @param {json} [init] - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + async post(apiName, path, init) { + if (!this._api) { + try { + await this.createInstance(); + } catch (error) { + return Promise.reject(error); + } + } + + const endpoint = this._api.endpoint(apiName); + if (endpoint.length === 0) { + return Promise.reject('API ' + apiName + ' does not exist'); + } + return this._api.post(endpoint + path, init); + } + + /** + * Make a PUT request + * @param {string} apiName - The api name of the request + * @param {string} path - The path of the request + * @param {json} [init] - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + async put(apiName, path, init) { + if (!this._api) { + try { + await this.createInstance(); + } catch (error) { + return Promise.reject(error); + } + } + + const endpoint = this._api.endpoint(apiName); + if (endpoint.length === 0) { + return Promise.reject('API ' + apiName + ' does not exist'); + } + return this._api.put(endpoint + path, init); + } + + /** + * Make a PATCH request + * @param {string} apiName - The api name of the request + * @param {string} path - The path of the request + * @param {json} [init] - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + async patch(apiName, path, init) { + if (!this._api) { + try { + await this.createInstance(); + } catch (error) { + return Promise.reject(error); + } + } + + const endpoint = this._api.endpoint(apiName); + if (endpoint.length === 0) { + return Promise.reject('API ' + apiName + ' does not exist'); + } + return this._api.patch(endpoint + path, init); + } + + /** + * Make a DEL request + * @param {string} apiName - The api name of the request + * @param {string} path - The path of the request + * @param {json} [init] - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + async del(apiName, path, init) { + if (!this._api) { + try { + await this.createInstance(); + } catch (error) { + return Promise.reject(error); + } + } + + const endpoint = this._api.endpoint(apiName); + if (endpoint.length === 0) { + return Promise.reject('API ' + apiName + ' does not exist'); + } + return this._api.del(endpoint + path, init); + } + + /** + * Make a HEAD request + * @param {string} apiName - The api name of the request + * @param {string} path - The path of the request + * @param {json} [init] - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + async head(apiName, path, init) { + if (!this._api) { + try { + await this.createInstance(); + } catch (error) { + return Promise.reject(error); + } + } + + const endpoint = this._api.endpoint(apiName); + if (endpoint.length === 0) { + return Promise.reject('API ' + apiName + ' does not exist'); + } + return this._api.head(endpoint + path, init); + } + + /** + * Getting endpoint for API + * @param {string} apiName - The name of the api + * @return {string} - The endpoint of the api + */ + async endpoint(apiName) { + if (!this._api) { + try { + await this.createInstance(); + } catch (error) { + return Promise.reject(error); + } + } + return this._api.endpoint(apiName); + } + + private async _headerBasedAuth(defaultAuthenticationType?) { + const { + aws_appsync_authenticationType, + aws_appsync_apiKey: apiKey, + } = this._options; + const authenticationType = + defaultAuthenticationType || aws_appsync_authenticationType || 'AWS_IAM'; + let headers = {}; + + switch (authenticationType) { + case 'API_KEY': + if (!apiKey) { + throw new Error('No api-key configured'); + } + headers = { + Authorization: null, + 'X-Api-Key': apiKey, + }; + break; + case 'AWS_IAM': + const credentialsOK = await this._ensureCredentials(); + if (!credentialsOK) { + throw new Error('No credentials'); + } + break; + case 'OPENID_CONNECT': + const federatedInfo = await Cache.getItem('federatedInfo'); + + if (!federatedInfo || !federatedInfo.token) { + throw new Error('No federated jwt'); + } + headers = { + Authorization: federatedInfo.token, + }; + break; + case 'AMAZON_COGNITO_USER_POOLS': + const session = await Auth.currentSession(); + headers = { + Authorization: session.getAccessToken().getJwtToken(), + }; + break; + default: + headers = { + Authorization: null, + }; + break; + } + + return headers; + } + + /** + * to get the operation type + * @param operation + */ + getGraphqlOperationType(operation) { + const doc = parse(operation); + const { + definitions: [{ operation: operationType }], + } = doc; + + return operationType; + } + + /** + * Executes a GraphQL operation + * + * @param {GraphQLOptions} GraphQL Options + * @returns {Promise | Observable} + */ + graphql({ query: paramQuery, variables = {}, authMode }: GraphQLOptions) { + const query = + typeof paramQuery === 'string' + ? parse(paramQuery) + : parse(print(paramQuery)); + + const [operationDef = {}] = query.definitions.filter( + def => def.kind === 'OperationDefinition' + ); + const { + operation: operationType, + } = operationDef as OperationDefinitionNode; + + switch (operationType) { + case 'query': + case 'mutation': + return this._graphql({ query, variables, authMode }); + case 'subscription': + return this._graphqlSubscribe({ query, variables, authMode }); + } + + throw new Error(`invalid operation type: ${operationType}`); + } + + private async _graphql( + { query, variables, authMode }: GraphQLOptions, + additionalHeaders = {} + ): Promise { + if (!this._api) { + await this.createInstance(); + } + + const { + aws_appsync_region: region, + aws_appsync_graphqlEndpoint: appSyncGraphqlEndpoint, + graphql_headers = () => ({}), + graphql_endpoint: customGraphqlEndpoint, + graphql_endpoint_iam_region: customEndpointRegion, + } = this._options; + + const headers = { + ...(!customGraphqlEndpoint && (await this._headerBasedAuth(authMode))), + ...(customGraphqlEndpoint && + (customEndpointRegion + ? await this._headerBasedAuth(authMode) + : { Authorization: null })), + ...additionalHeaders, + ...(await graphql_headers({ query, variables })), + }; + + const body = { + query: print(query), + variables, + }; + + const init = { + headers, + body, + signerServiceInfo: { + service: !customGraphqlEndpoint ? 'appsync' : 'execute-api', + region: !customGraphqlEndpoint ? region : customEndpointRegion, + }, + }; + + const endpoint = customGraphqlEndpoint || appSyncGraphqlEndpoint; + + if (!endpoint) { + const error = new GraphQLError('No graphql endpoint provided.'); + + throw { + data: {}, + errors: [error], + }; + } + + let response; + try { + response = await this._api.post(endpoint, init); + } catch (err) { + response = { + data: {}, + errors: [new GraphQLError(err.message)], + }; + } + + const { errors } = response; + + if (errors && errors.length) { + throw response; + } + + return response; + } + + private clientIdentifier = uuid(); + + private _graphqlSubscribe({ + query, + variables, + authMode, + }: GraphQLOptions): Observable { + if (Amplify.PubSub && typeof Amplify.PubSub.subscribe === 'function') { + return new Observable(observer => { + let handle = null; + + (async () => { + const { aws_appsync_authenticationType } = this._options; + const authenticationType = authMode || aws_appsync_authenticationType; + const additionalheaders = { + ...(authenticationType === 'API_KEY' + ? { + 'x-amz-subscriber-id': this.clientIdentifier, + } + : {}), + }; + + try { + const { + extensions: { subscription }, + } = await this._graphql( + { query, variables, authMode }, + additionalheaders + ); + + const { newSubscriptions } = subscription; + + const newTopics = Object.getOwnPropertyNames(newSubscriptions).map( + p => newSubscriptions[p].topic + ); + + const observable = Amplify.PubSub.subscribe(newTopics, { + ...subscription, + provider: INTERNAL_AWS_APPSYNC_PUBSUB_PROVIDER, + }); + + handle = observable.subscribe({ + next: data => observer.next(data), + complete: () => observer.complete(), + error: data => { + const error = { ...data }; + if (!error.errors) { + error.errors = [ + { + ...new GraphQLError('Network Error'), + }, + ]; + } + observer.error(error); + }, + }); + } catch (error) { + observer.error(error); + } + })(); + + return () => { + if (handle) { + handle.unsubscribe(); + } + }; + }); + } else { + logger.debug('No pubsub module applied for subscription'); + throw new Error('No pubsub module applied for subscription'); + } + } + + /** + * @private + */ + _ensureCredentials() { + return Credentials.get() + .then(credentials => { + if (!credentials) return false; + const cred = Credentials.shear(credentials); + logger.debug('set credentials for api', cred); + + return true; + }) + .catch(err => { + logger.warn('ensure credentials error', err); + return false; + }); + } } diff --git a/packages/api/src/RestClient.ts b/packages/api/src/RestClient.ts index 46d00a11311..0c9ef2ace0d 100644 --- a/packages/api/src/RestClient.ts +++ b/packages/api/src/RestClient.ts @@ -11,13 +11,18 @@ * and limitations under the License. */ -import { ConsoleLogger as Logger, Signer, Platform, Credentials } from '@aws-amplify/core'; +import { + ConsoleLogger as Logger, + Signer, + Platform, + Credentials, +} from '@aws-amplify/core'; import { RestClientOptions, AWSCredentials, apiOptions } from './types'; import axios from 'axios'; const logger = new Logger('RestClient'), - urlLib = require('url'); + urlLib = require('url'); /** * HTTP Client for REST requests. Send and receive JSON data. @@ -33,20 +38,20 @@ restClient.get('...') */ export class RestClient { - private _options; - private _region: string = 'us-east-1'; // this will be updated by endpoint function - private _service: string = 'execute-api'; // this can be updated by endpoint function - private _custom_header = undefined; // this can be updated by endpoint function - /** - * @param {RestClientOptions} [options] - Instance options - */ - constructor(options: apiOptions) { - const { endpoints } = options; - this._options = options; - logger.debug('API Options', this._options); - } - - /** + private _options; + private _region: string = 'us-east-1'; // this will be updated by endpoint function + private _service: string = 'execute-api'; // this can be updated by endpoint function + private _custom_header = undefined; // this can be updated by endpoint function + /** + * @param {RestClientOptions} [options] - Instance options + */ + constructor(options: apiOptions) { + const { endpoints } = options; + this._options = options; + logger.debug('API Options', this._options); + } + + /** * Update AWS credentials * @param {AWSCredentials} credentials - AWS credentials * @@ -54,246 +59,255 @@ export class RestClient { this.options.credentials = credentials; } */ - /** - * Basic HTTP request. Customizable - * @param {string} url - Full request URL - * @param {string} method - Request HTTP method - * @param {json} [init] - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - async ajax(url: string, method: string, init) { - logger.debug(method + ' ' + url); - - const parsed_url = this._parseUrl(url); - - const params = { - method, - url, - host: parsed_url.host, - path: parsed_url.path, - headers: {}, - data: null, - responseType: 'json', - timeout: 0 - }; - - let libraryHeaders = {}; - - if (Platform.isReactNative) { - const userAgent = Platform.userAgent || 'aws-amplify/0.1.x'; - libraryHeaders = { - 'User-Agent': userAgent - }; - } - - const initParams = Object.assign({}, init); - const isAllResponse = initParams.response; - if (initParams.body) { - libraryHeaders['Content-Type'] = 'application/json; charset=UTF-8'; - params.data = JSON.stringify(initParams.body); - } - if (initParams.responseType) { - params.responseType = initParams.responseType; - } - if (initParams.withCredentials) { - params['withCredentials'] = initParams.withCredentials; - } - if (initParams.timeout) { - params.timeout = initParams.timeout; - } - - params['signerServiceInfo'] = initParams.signerServiceInfo; - - // custom_header callback - const custom_header = this._custom_header ? await this._custom_header() : undefined; - - params.headers = { ...libraryHeaders, ...(custom_header),...initParams.headers }; - - // Intentionally discarding search - const { search, ...parsedUrl } = urlLib.parse(url, true, true); - params.url = urlLib.format({ - ...parsedUrl, - query: { - ...parsedUrl.query, - ...(initParams.queryStringParameters || {}) - } - }); - - // Do not sign the request if client has added 'Authorization' header, - // which means custom authorizer. - if (typeof params.headers['Authorization'] !== 'undefined') { - params.headers = Object.keys(params.headers).reduce((acc, k) => { - if (params.headers[k]) { - acc[k] = params.headers[k]; - } - return acc; - // tslint:disable-next-line:align - }, {}); - return this._request(params, isAllResponse); - - } - - // Signing the request in case there credentials are available - return Credentials.get() - .then( - credentials => this._signed({ ...params }, credentials, isAllResponse), - err => { - logger.debug('No credentials available, the request will be unsigned'); - return this._request(params, isAllResponse); - } - ); - } - - /** - * GET HTTP request - * @param {string} url - Full request URL - * @param {JSON} init - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - get(url: string, init) { - return this.ajax(url, 'GET', init); - } - - /** - * PUT HTTP request - * @param {string} url - Full request URL - * @param {json} init - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - put(url: string, init) { - return this.ajax(url, 'PUT', init); - } - - /** - * PATCH HTTP request - * @param {string} url - Full request URL - * @param {json} init - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - patch(url: string, init) { - return this.ajax(url, 'PATCH', init); - } - - /** - * POST HTTP request - * @param {string} url - Full request URL - * @param {json} init - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - post(url: string, init) { - return this.ajax(url, 'POST', init); - } - - /** - * DELETE HTTP request - * @param {string} url - Full request URL - * @param {json} init - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - del(url: string, init) { - return this.ajax(url, 'DELETE', init); - } - - /** - * HEAD HTTP request - * @param {string} url - Full request URL - * @param {json} init - Request extra params - * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. - */ - head(url: string, init) { - return this.ajax(url, 'HEAD', init); - } - - /** - * Getting endpoint for API - * @param {string} apiName - The name of the api - * @return {string} - The endpoint of the api - */ - endpoint(apiName: string) { - const cloud_logic_array = this._options.endpoints; - let response = ''; - - if(!Array.isArray(cloud_logic_array)) { - return response; - } - - cloud_logic_array.forEach((v) => { - if (v.name === apiName) { - response = v.endpoint; - if (typeof v.region === 'string') { - this._region = v.region; - } else if (typeof this._options.region === 'string') { - this._region = this._options.region; - } - if (typeof v.service === 'string') { - this._service = v.service || 'execute-api'; - } else { - this._service = 'execute-api'; - } - if (typeof v.custom_header === 'function') { - this._custom_header = v.custom_header; - } else { - this._custom_header = undefined; - } - } - }); - return response; - } - - /** private methods **/ - - private _signed(params, credentials, isAllResponse) { - - const { signerServiceInfo: signerServiceInfoParams, ...otherParams } = params; - - const endpoint_region: string = this._region || this._options.region; - const endpoint_service: string = this._service || this._options.service; - - const creds = { - secret_key: credentials.secretAccessKey, - access_key: credentials.accessKeyId, - session_token: credentials.sessionToken, - }; - - const endpointInfo = { - region: endpoint_region, - service: endpoint_service, - }; - - const signerServiceInfo = Object.assign(endpointInfo, signerServiceInfoParams); - - const signed_params = Signer.sign(otherParams, creds, signerServiceInfo); - - if (signed_params.data) { - signed_params.body = signed_params.data; - } - - logger.debug('Signed Request: ', signed_params); - - delete signed_params.headers['host']; - return axios(signed_params) - .then(response => isAllResponse ? response : response.data) - .catch((error) => { - logger.debug(error); - throw error; - }); - } - - private _request(params, isAllResponse = false) { - return axios(params) - .then(response => isAllResponse ? response : response.data) - .catch((error) => { - logger.debug(error); - throw error; - }); - } - - private _parseUrl(url) { - const parts = url.split('/'); - - return { - host: parts[2], - path: '/' + parts.slice(3).join('/') - }; - } + /** + * Basic HTTP request. Customizable + * @param {string} url - Full request URL + * @param {string} method - Request HTTP method + * @param {json} [init] - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + async ajax(url: string, method: string, init) { + logger.debug(method + ' ' + url); + + const parsed_url = this._parseUrl(url); + + const params = { + method, + url, + host: parsed_url.host, + path: parsed_url.path, + headers: {}, + data: null, + responseType: 'json', + timeout: 0, + }; + + let libraryHeaders = {}; + + if (Platform.isReactNative) { + const userAgent = Platform.userAgent || 'aws-amplify/0.1.x'; + libraryHeaders = { + 'User-Agent': userAgent, + }; + } + + const initParams = Object.assign({}, init); + const isAllResponse = initParams.response; + if (initParams.body) { + libraryHeaders['Content-Type'] = 'application/json; charset=UTF-8'; + params.data = JSON.stringify(initParams.body); + } + if (initParams.responseType) { + params.responseType = initParams.responseType; + } + if (initParams.withCredentials) { + params['withCredentials'] = initParams.withCredentials; + } + if (initParams.timeout) { + params.timeout = initParams.timeout; + } + + params['signerServiceInfo'] = initParams.signerServiceInfo; + + // custom_header callback + const custom_header = this._custom_header + ? await this._custom_header() + : undefined; + + params.headers = { + ...libraryHeaders, + ...custom_header, + ...initParams.headers, + }; + + // Intentionally discarding search + const { search, ...parsedUrl } = urlLib.parse(url, true, true); + params.url = urlLib.format({ + ...parsedUrl, + query: { + ...parsedUrl.query, + ...(initParams.queryStringParameters || {}), + }, + }); + + // Do not sign the request if client has added 'Authorization' header, + // which means custom authorizer. + if (typeof params.headers['Authorization'] !== 'undefined') { + params.headers = Object.keys(params.headers).reduce((acc, k) => { + if (params.headers[k]) { + acc[k] = params.headers[k]; + } + return acc; + // tslint:disable-next-line:align + }, {}); + return this._request(params, isAllResponse); + } + + // Signing the request in case there credentials are available + return Credentials.get().then( + credentials => this._signed({ ...params }, credentials, isAllResponse), + err => { + logger.debug('No credentials available, the request will be unsigned'); + return this._request(params, isAllResponse); + } + ); + } + + /** + * GET HTTP request + * @param {string} url - Full request URL + * @param {JSON} init - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + get(url: string, init) { + return this.ajax(url, 'GET', init); + } + + /** + * PUT HTTP request + * @param {string} url - Full request URL + * @param {json} init - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + put(url: string, init) { + return this.ajax(url, 'PUT', init); + } + + /** + * PATCH HTTP request + * @param {string} url - Full request URL + * @param {json} init - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + patch(url: string, init) { + return this.ajax(url, 'PATCH', init); + } + + /** + * POST HTTP request + * @param {string} url - Full request URL + * @param {json} init - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + post(url: string, init) { + return this.ajax(url, 'POST', init); + } + + /** + * DELETE HTTP request + * @param {string} url - Full request URL + * @param {json} init - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + del(url: string, init) { + return this.ajax(url, 'DELETE', init); + } + + /** + * HEAD HTTP request + * @param {string} url - Full request URL + * @param {json} init - Request extra params + * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful. + */ + head(url: string, init) { + return this.ajax(url, 'HEAD', init); + } + + /** + * Getting endpoint for API + * @param {string} apiName - The name of the api + * @return {string} - The endpoint of the api + */ + endpoint(apiName: string) { + const cloud_logic_array = this._options.endpoints; + let response = ''; + + if (!Array.isArray(cloud_logic_array)) { + return response; + } + + cloud_logic_array.forEach(v => { + if (v.name === apiName) { + response = v.endpoint; + if (typeof v.region === 'string') { + this._region = v.region; + } else if (typeof this._options.region === 'string') { + this._region = this._options.region; + } + if (typeof v.service === 'string') { + this._service = v.service || 'execute-api'; + } else { + this._service = 'execute-api'; + } + if (typeof v.custom_header === 'function') { + this._custom_header = v.custom_header; + } else { + this._custom_header = undefined; + } + } + }); + return response; + } + + /** private methods **/ + + private _signed(params, credentials, isAllResponse) { + const { + signerServiceInfo: signerServiceInfoParams, + ...otherParams + } = params; + + const endpoint_region: string = this._region || this._options.region; + const endpoint_service: string = this._service || this._options.service; + + const creds = { + secret_key: credentials.secretAccessKey, + access_key: credentials.accessKeyId, + session_token: credentials.sessionToken, + }; + + const endpointInfo = { + region: endpoint_region, + service: endpoint_service, + }; + + const signerServiceInfo = Object.assign( + endpointInfo, + signerServiceInfoParams + ); + + const signed_params = Signer.sign(otherParams, creds, signerServiceInfo); + + if (signed_params.data) { + signed_params.body = signed_params.data; + } + + logger.debug('Signed Request: ', signed_params); + + delete signed_params.headers['host']; + return axios(signed_params) + .then(response => (isAllResponse ? response : response.data)) + .catch(error => { + logger.debug(error); + throw error; + }); + } + + private _request(params, isAllResponse = false) { + return axios(params) + .then(response => (isAllResponse ? response : response.data)) + .catch(error => { + logger.debug(error); + throw error; + }); + } + + private _parseUrl(url) { + const parts = url.split('/'); + + return { + host: parts[2], + path: '/' + parts.slice(3).join('/'), + }; + } } diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 0a1d3f0007e..9910f2581c5 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -20,8 +20,8 @@ const logger = new Logger('API'); let _instance: APIClass = null; if (!_instance) { - logger.debug('Create API Instance'); - _instance = new APIClass(null); + logger.debug('Create API Instance'); + _instance = new APIClass(null); } const API = _instance; diff --git a/packages/api/src/types/index.ts b/packages/api/src/types/index.ts index 54d83d73076..8466491b4d5 100644 --- a/packages/api/src/types/index.ts +++ b/packages/api/src/types/index.ts @@ -13,75 +13,74 @@ import { DocumentNode } from 'graphql/language/ast'; /** -* RestClient instance options -*/ + * RestClient instance options + */ export class RestClientOptions { - /** AWS credentials */ - credentials: AWSCredentials; + /** AWS credentials */ + credentials: AWSCredentials; - /** - * Lookup key of AWS credentials. - * If credentials not provided then lookup from sessionStorage. - * Default 'awsCredentials' - */ - credentials_key: string; + /** + * Lookup key of AWS credentials. + * If credentials not provided then lookup from sessionStorage. + * Default 'awsCredentials' + */ + credentials_key: string; - /** Additional headers for all requests send by this client. e.g. user-agent */ - headers: object; + /** Additional headers for all requests send by this client. e.g. user-agent */ + headers: object; - constructor() { - this.credentials_key = 'awsCredentials'; - this.headers = {}; - } + constructor() { + this.credentials_key = 'awsCredentials'; + this.headers = {}; + } } /** -* AWS credentials needed for RestClient -*/ + * AWS credentials needed for RestClient + */ export class AWSCredentials { - /** - * Secret Access Key - * - * [Access Key ID and Secret Access Key] - * (http://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys) - */ - secretAccessKey: string; + /** + * Secret Access Key + * + * [Access Key ID and Secret Access Key] + * (http://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys) + */ + secretAccessKey: string; - /** - * Access Key ID - * - * [Access Key ID and Secret Access Key] - * (http://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys) - */ - accessKeyId: string; + /** + * Access Key ID + * + * [Access Key ID and Secret Access Key] + * (http://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys) + */ + accessKeyId: string; - /** Access Token of current session */ - sessionToken: string; + /** Access Token of current session */ + sessionToken: string; } // TODO: remove this once unauth creds are figured out export interface apiOptions { - headers: object; - endpoints: object; - credentials?: object; + headers: object; + endpoints: object; + credentials?: object; } export interface GraphQLOptions { - query: string | DocumentNode, - variables?: object, - authMode?: GRAPHQL_AUTH_MODE, + query: string | DocumentNode; + variables?: object; + authMode?: GRAPHQL_AUTH_MODE; } export enum GRAPHQL_AUTH_MODE { - API_KEY = "API_KEY", - AWS_IAM = "AWS_IAM", - OPENID_CONNECT = "OPENID_CONNECT", - AMAZON_COGNITO_USER_POOLS = "AMAZON_COGNITO_USER_POOLS", - + API_KEY = 'API_KEY', + AWS_IAM = 'AWS_IAM', + OPENID_CONNECT = 'OPENID_CONNECT', + AMAZON_COGNITO_USER_POOLS = 'AMAZON_COGNITO_USER_POOLS', } export interface GraphQLResult { - data?: object, - errors?: [object], - extensions?: { [key: string]: any }, + data?: object; + errors?: [object]; + extensions?: { [key: string]: any }; } diff --git a/packages/api/tslint.json b/packages/api/tslint.json index 9d5f01d0502..1bb9e144d24 100644 --- a/packages/api/tslint.json +++ b/packages/api/tslint.json @@ -1,72 +1,45 @@ - { - "defaultSeverity": "error", - "plugins": [ - "prettier" - ], - "extends": [ - //"tslint-config-airbnb" - ], - "jsRules": {}, - "rules": { - "prefer-const": true, - "max-line-length": [true, 120], - "no-empty-interface": true, - "no-var-keyword": true, - "object-literal-shorthand": true, - "no-eval": true, - "space-before-function-paren": [ - true, - { - "anonymous": "never", - "named": "never" - } - ], - "no-parameter-reassignment": true, - "align": [ - true, - "arguments", - "parameters" - ], - "no-duplicate-imports": true, - "one-variable-per-declaration": [ - false, - "ignore-for-loop" - ], - "triple-equals": [ - true, - "allow-null-check" - ], - "no-boolean-literal-compare": true, - "comment-format": [ - true, - "check-space" - ], - "indent": [ - true, - "space", - 2 - ], - "whitespace": [ - false, - "check-branch", - "check-decl", - "check-operator", - "check-preblock" - ], - "eofline": true, - "variable-name": [ - true, - "check-format", // 22.2 - "allow-pascal-case", - "allow-snake-case", - "allow-leading-underscore" - ], - "semicolon": [ - true, - "always", - "ignore-interfaces" - ] - }, - "rulesDirectory": [] -} \ No newline at end of file + "defaultSeverity": "error", + "plugins": ["prettier"], + "extends": [], + "jsRules": {}, + "rules": { + "prefer-const": true, + "max-line-length": [true, 120], + "no-empty-interface": true, + "no-var-keyword": true, + "object-literal-shorthand": true, + "no-eval": true, + "space-before-function-paren": [ + true, + { + "anonymous": "never", + "named": "never" + } + ], + "no-parameter-reassignment": true, + "align": [true, "parameters"], + "no-duplicate-imports": true, + "one-variable-per-declaration": [false, "ignore-for-loop"], + "triple-equals": [true, "allow-null-check"], + "comment-format": [true, "check-space"], + "indent": [false], + "whitespace": [ + false, + "check-branch", + "check-decl", + "check-operator", + "check-preblock" + ], + "eofline": true, + "variable-name": [ + true, + "check-format", + "allow-pascal-case", + "allow-snake-case", + "allow-leading-underscore" + ], + "semicolon": [true, "always", "ignore-interfaces"] + }, + "rulesDirectory": [] +} diff --git a/packages/api/webpack.config.js b/packages/api/webpack.config.js index 40a2c0f9ce3..a1c8bd7ee3a 100644 --- a/packages/api/webpack.config.js +++ b/packages/api/webpack.config.js @@ -1,56 +1,57 @@ const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); -const CompressionPlugin = require("compression-webpack-plugin") +const CompressionPlugin = require('compression-webpack-plugin'); module.exports = { - entry: { - 'aws-amplify-api': './src/index.ts', - 'aws-amplify-api.min': './src/index.ts' - }, - output: { - filename: '[name].js', - path: __dirname + '/dist', - library: 'aws_amplify_api', - libraryTarget: 'umd', - umdNamedDefine: true, - devtoolModuleFilenameTemplate: require('../aws-amplify/webpack-utils').devtoolModuleFilenameTemplate - }, - // Enable sourcemaps for debugging webpack's output. - devtool: 'source-map', - resolve: { - // Add '.ts' and '.tsx' as resolvable extensions. - extensions: ['.ts', '.tsx', '.js', '.json'] - }, - plugins: [ - new UglifyJsPlugin({ - minimize: true, - sourceMap: true, - include: /\.min\.js$/, - }), - new CompressionPlugin({ - include: /\.min\.js$/, - }) - ], - module: { - rules: [ - // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'. - { - test: /\.tsx?$/, - loader: 'awesome-typescript-loader', - exclude: /node_modules/, - query: { - declaration: false - } - }, - // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. - //{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' }, - { - test: /\.jsx?$/, - exclude: /node_modules/, - loader: 'babel-loader', - query: { - presets: ['react', 'es2015', 'stage-2'], - } - } - ] - } + entry: { + 'aws-amplify-api': './src/index.ts', + 'aws-amplify-api.min': './src/index.ts', + }, + output: { + filename: '[name].js', + path: __dirname + '/dist', + library: 'aws_amplify_api', + libraryTarget: 'umd', + umdNamedDefine: true, + devtoolModuleFilenameTemplate: require('../aws-amplify/webpack-utils') + .devtoolModuleFilenameTemplate, + }, + // Enable sourcemaps for debugging webpack's output. + devtool: 'source-map', + resolve: { + // Add '.ts' and '.tsx' as resolvable extensions. + extensions: ['.ts', '.tsx', '.js', '.json'], + }, + plugins: [ + new UglifyJsPlugin({ + minimize: true, + sourceMap: true, + include: /\.min\.js$/, + }), + new CompressionPlugin({ + include: /\.min\.js$/, + }), + ], + module: { + rules: [ + // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'. + { + test: /\.tsx?$/, + loader: 'awesome-typescript-loader', + exclude: /node_modules/, + query: { + declaration: false, + }, + }, + // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. + //{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' }, + { + test: /\.jsx?$/, + exclude: /node_modules/, + loader: 'babel-loader', + query: { + presets: ['react', 'es2015', 'stage-2'], + }, + }, + ], + }, }; diff --git a/packages/auth/CHANGELOG.md b/packages/auth/CHANGELOG.md index 64eb6f75cfc..b536e04a30e 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -7,1756 +7,1293 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package @aws-amplify/auth - - - - ## [1.3.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.3.0...@aws-amplify/auth@1.3.1) (2019-09-05) **Note:** Version bump only for package @aws-amplify/auth - - - - # [1.3.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.31...@aws-amplify/auth@1.3.0) (2019-09-04) - ### Features -* **@aws-amplify/auth:** Error messaging ([47ec74d](https://github.com/aws/aws-amplify/commit/47ec74d)) - - - - +- **@aws-amplify/auth:** Error messaging ([47ec74d](https://github.com/aws/aws-amplify/commit/47ec74d)) ## [1.2.31](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.30...@aws-amplify/auth@1.2.31) (2019-08-05) - ### Bug Fixes -* **@aws-amplify/auth:** Encode customState when storing to compare against incoming state for federated sign in ([#3784](https://github.com/aws/aws-amplify/issues/3784)) ([1824134](https://github.com/aws/aws-amplify/commit/1824134)) - - - - +- **@aws-amplify/auth:** Encode customState when storing to compare against incoming state for federated sign in ([#3784](https://github.com/aws/aws-amplify/issues/3784)) ([1824134](https://github.com/aws/aws-amplify/commit/1824134)) ## [1.2.30](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.29...@aws-amplify/auth@1.2.30) (2019-07-31) **Note:** Version bump only for package @aws-amplify/auth - - - - ## [1.2.29](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.28...@aws-amplify/auth@1.2.29) (2019-07-30) - ### Bug Fixes -* **@aws-amplify/auth:** Improve OAuth flow in react native ([#3698](https://github.com/aws/aws-amplify/issues/3698)) ([799a1cf](https://github.com/aws/aws-amplify/commit/799a1cf)), closes [#3681](https://github.com/aws/aws-amplify/issues/3681) - - - - +- **@aws-amplify/auth:** Improve OAuth flow in react native ([#3698](https://github.com/aws/aws-amplify/issues/3698)) ([799a1cf](https://github.com/aws/aws-amplify/commit/799a1cf)), closes [#3681](https://github.com/aws/aws-amplify/issues/3681) ## [1.2.28](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.26...@aws-amplify/auth@1.2.28) (2019-07-18) **Note:** Version bump only for package @aws-amplify/auth - - - - -## [1.2.27-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.27-unstable.0...@aws-amplify/auth@1.2.27-unstable.1) (2019-07-12) +## [1.2.27-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.27-unstable.0...@aws-amplify/auth@1.2.27-unstable.1) (2019-07-12) ### Bug Fixes -* **@aws-amplify/auth, aws-amplify-react-native:** Fix OAuth flow in react native ([#3633](https://github.com/aws/aws-amplify/issues/3633)) ([82e74fc](https://github.com/aws/aws-amplify/commit/82e74fc)), closes [#3399](https://github.com/aws/aws-amplify/issues/3399) [#3576](https://github.com/aws/aws-amplify/issues/3576) [#3247](https://github.com/aws/aws-amplify/issues/3247) [#3592](https://github.com/aws/aws-amplify/issues/3592) [#3210](https://github.com/aws/aws-amplify/issues/3210) - - - +- **@aws-amplify/auth, aws-amplify-react-native:** Fix OAuth flow in react native ([#3633](https://github.com/aws/aws-amplify/issues/3633)) ([82e74fc](https://github.com/aws/aws-amplify/commit/82e74fc)), closes [#3399](https://github.com/aws/aws-amplify/issues/3399) [#3576](https://github.com/aws/aws-amplify/issues/3576) [#3247](https://github.com/aws/aws-amplify/issues/3247) [#3592](https://github.com/aws/aws-amplify/issues/3592) [#3210](https://github.com/aws/aws-amplify/issues/3210) -## [1.2.27-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.26...@aws-amplify/auth@1.2.27-unstable.0) (2019-07-10) - - +## [1.2.27-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.26...@aws-amplify/auth@1.2.27-unstable.0) (2019-07-10) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.26](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.26-unstable.0...@aws-amplify/auth@1.2.26) (2019-07-09) - - +## [1.2.26](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.26-unstable.0...@aws-amplify/auth@1.2.26) (2019-07-09) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.26-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.25...@aws-amplify/auth@1.2.26-unstable.0) (2019-06-27) +## [1.2.26-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.25...@aws-amplify/auth@1.2.26-unstable.0) (2019-06-27) ### Bug Fixes -* **@aws-amplify/auth:** Handle case when `signOut()` promise is rejected ([#3179](https://github.com/aws/aws-amplify/issues/3179)) ([0a2efd4](https://github.com/aws/aws-amplify/commit/0a2efd4)) - - - +- **@aws-amplify/auth:** Handle case when `signOut()` promise is rejected ([#3179](https://github.com/aws/aws-amplify/issues/3179)) ([0a2efd4](https://github.com/aws/aws-amplify/commit/0a2efd4)) -## [1.2.25](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.25-unstable.3...@aws-amplify/auth@1.2.25) (2019-06-17) - - +## [1.2.25](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.25-unstable.3...@aws-amplify/auth@1.2.25) (2019-06-17) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.25-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.25-unstable.2...@aws-amplify/auth@1.2.25-unstable.3) (2019-06-14) - - +## [1.2.25-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.25-unstable.2...@aws-amplify/auth@1.2.25-unstable.3) (2019-06-14) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.25-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.25-unstable.1...@aws-amplify/auth@1.2.25-unstable.2) (2019-05-28) - - +## [1.2.25-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.25-unstable.1...@aws-amplify/auth@1.2.25-unstable.2) (2019-05-28) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.25-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.24...@aws-amplify/auth@1.2.25-unstable.1) (2019-05-24) +## [1.2.25-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.24...@aws-amplify/auth@1.2.25-unstable.1) (2019-05-24) ### Bug Fixes -* **@aws-amplify/auth:** check if storage object is valid or not ([d93d36d](https://github.com/aws/aws-amplify/commit/d93d36d)) -* **aws-amplify:** manual version bumps for lerna issue ([9ce5a72](https://github.com/aws/aws-amplify/commit/9ce5a72)) - - - +- **@aws-amplify/auth:** check if storage object is valid or not ([d93d36d](https://github.com/aws/aws-amplify/commit/d93d36d)) +- **aws-amplify:** manual version bumps for lerna issue ([9ce5a72](https://github.com/aws/aws-amplify/commit/9ce5a72)) -## [1.2.24](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.24-unstable.1...@aws-amplify/auth@1.2.24) (2019-05-14) - - +## [1.2.24](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.24-unstable.1...@aws-amplify/auth@1.2.24) (2019-05-14) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.24-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.24-unstable.0...@aws-amplify/auth@1.2.24-unstable.1) (2019-05-13) - - +## [1.2.24-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.24-unstable.0...@aws-amplify/auth@1.2.24-unstable.1) (2019-05-13) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.24-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23...@aws-amplify/auth@1.2.24-unstable.0) (2019-05-09) +## [1.2.24-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23...@aws-amplify/auth@1.2.24-unstable.0) (2019-05-09) ### Bug Fixes -* **@aws-amplify/auth:** react-native - guard for window ([9254312](https://github.com/aws/aws-amplify/commit/9254312)) - - - +- **@aws-amplify/auth:** react-native - guard for window ([9254312](https://github.com/aws/aws-amplify/commit/9254312)) -## [1.2.23](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.8...@aws-amplify/auth@1.2.23) (2019-05-06) - - +## [1.2.23](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.8...@aws-amplify/auth@1.2.23) (2019-05-06) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.23-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.7...@aws-amplify/auth@1.2.23-unstable.8) (2019-05-06) - - +## [1.2.23-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.7...@aws-amplify/auth@1.2.23-unstable.8) (2019-05-06) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.23-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.6...@aws-amplify/auth@1.2.23-unstable.7) (2019-04-26) +## [1.2.23-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.6...@aws-amplify/auth@1.2.23-unstable.7) (2019-04-26) ### Bug Fixes -* **@aws-amplify/auth:** User may not be fully signed out ([#3172](https://github.com/aws/aws-amplify/issues/3172)) ([2678cc3](https://github.com/aws/aws-amplify/commit/2678cc3)), closes [#3117](https://github.com/aws/aws-amplify/issues/3117) - - - +- **@aws-amplify/auth:** User may not be fully signed out ([#3172](https://github.com/aws/aws-amplify/issues/3172)) ([2678cc3](https://github.com/aws/aws-amplify/commit/2678cc3)), closes [#3117](https://github.com/aws/aws-amplify/issues/3117) -## [1.2.23-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.5...@aws-amplify/auth@1.2.23-unstable.6) (2019-04-26) - - +## [1.2.23-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.5...@aws-amplify/auth@1.2.23-unstable.6) (2019-04-26) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.23-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.4...@aws-amplify/auth@1.2.23-unstable.5) (2019-04-24) +## [1.2.23-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.4...@aws-amplify/auth@1.2.23-unstable.5) (2019-04-24) ### Bug Fixes -* **@aws-amplify/auth:** Always bypass the cache on setPreferredMFA method ([3b28c98](https://github.com/aws/aws-amplify/commit/3b28c98)) - +- **@aws-amplify/auth:** Always bypass the cache on setPreferredMFA method ([3b28c98](https://github.com/aws/aws-amplify/commit/3b28c98)) ### Features -* **@aws-amplify/auth:** Allow bypassing cache on setPreferredMFA and getPreferredMFA methods ([83a8ccf](https://github.com/aws/aws-amplify/commit/83a8ccf)) - - - +- **@aws-amplify/auth:** Allow bypassing cache on setPreferredMFA and getPreferredMFA methods ([83a8ccf](https://github.com/aws/aws-amplify/commit/83a8ccf)) -## [1.2.23-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.3...@aws-amplify/auth@1.2.23-unstable.4) (2019-04-24) +## [1.2.23-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.3...@aws-amplify/auth@1.2.23-unstable.4) (2019-04-24) ### Bug Fixes -* **@aws-amplify/auth:** fix 'Not Supported' error on SSR ([7f7e93d](https://github.com/aws/aws-amplify/commit/7f7e93d)) - - - +- **@aws-amplify/auth:** fix 'Not Supported' error on SSR ([7f7e93d](https://github.com/aws/aws-amplify/commit/7f7e93d)) -## [1.2.23-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.2...@aws-amplify/auth@1.2.23-unstable.3) (2019-04-17) - - +## [1.2.23-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.2...@aws-amplify/auth@1.2.23-unstable.3) (2019-04-17) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.23-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.1...@aws-amplify/auth@1.2.23-unstable.2) (2019-04-16) +## [1.2.23-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.1...@aws-amplify/auth@1.2.23-unstable.2) (2019-04-16) ### Bug Fixes -* **@aws-amplify/auth:** throw error when passing empty object to storage or cookieStorage in configuration ([816a827](https://github.com/aws/aws-amplify/commit/816a827)) - - - +- **@aws-amplify/auth:** throw error when passing empty object to storage or cookieStorage in configuration ([816a827](https://github.com/aws/aws-amplify/commit/816a827)) -## [1.2.23-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.0...@aws-amplify/auth@1.2.23-unstable.1) (2019-04-12) - - +## [1.2.23-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.23-unstable.0...@aws-amplify/auth@1.2.23-unstable.1) (2019-04-12) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.23-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.22...@aws-amplify/auth@1.2.23-unstable.0) (2019-04-12) - - +## [1.2.23-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.22...@aws-amplify/auth@1.2.23-unstable.0) (2019-04-12) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.22](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.22-unstable.0...@aws-amplify/auth@1.2.22) (2019-04-11) - - +## [1.2.22](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.22-unstable.0...@aws-amplify/auth@1.2.22) (2019-04-11) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.22-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.21...@aws-amplify/auth@1.2.22-unstable.0) (2019-04-10) +## [1.2.22-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.21...@aws-amplify/auth@1.2.22-unstable.0) (2019-04-10) ### Bug Fixes -* **@aws-amplify/auth:** Valide OAuth state only when generated by Amlify ([#3069](https://github.com/aws/aws-amplify/issues/3069)) ([30e828f](https://github.com/aws/aws-amplify/commit/30e828f)), closes [#3054](https://github.com/aws/aws-amplify/issues/3054) [#3055](https://github.com/aws/aws-amplify/issues/3055) - - - +- **@aws-amplify/auth:** Valide OAuth state only when generated by Amlify ([#3069](https://github.com/aws/aws-amplify/issues/3069)) ([30e828f](https://github.com/aws/aws-amplify/commit/30e828f)), closes [#3054](https://github.com/aws/aws-amplify/issues/3054) [#3055](https://github.com/aws/aws-amplify/issues/3055) -## [1.2.21](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.21-unstable.1...@aws-amplify/auth@1.2.21) (2019-04-09) - - +## [1.2.21](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.21-unstable.1...@aws-amplify/auth@1.2.21) (2019-04-09) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.21-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.21-unstable.0...@aws-amplify/auth@1.2.21-unstable.1) (2019-04-08) +## [1.2.21-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.21-unstable.0...@aws-amplify/auth@1.2.21-unstable.1) (2019-04-08) ### Features -* **@aws-amplify/auth:** Easier Federation with OAuth ([#3005](https://github.com/aws/aws-amplify/issues/3005)) ([76cde59](https://github.com/aws/aws-amplify/commit/76cde59)) - - - +- **@aws-amplify/auth:** Easier Federation with OAuth ([#3005](https://github.com/aws/aws-amplify/issues/3005)) ([76cde59](https://github.com/aws/aws-amplify/commit/76cde59)) -## [1.2.21-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.20...@aws-amplify/auth@1.2.21-unstable.0) (2019-04-07) - - +## [1.2.21-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.20...@aws-amplify/auth@1.2.21-unstable.0) (2019-04-07) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.20](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.20-unstable.1...@aws-amplify/auth@1.2.20) (2019-04-04) - - +## [1.2.20](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.20-unstable.1...@aws-amplify/auth@1.2.20) (2019-04-04) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.20-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.20-unstable.0...@aws-amplify/auth@1.2.20-unstable.1) (2019-04-04) - - +## [1.2.20-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.20-unstable.0...@aws-amplify/auth@1.2.20-unstable.1) (2019-04-04) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.20-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19...@aws-amplify/auth@1.2.20-unstable.0) (2019-04-02) - - +## [1.2.20-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19...@aws-amplify/auth@1.2.20-unstable.0) (2019-04-02) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.19](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.5...@aws-amplify/auth@1.2.19) (2019-03-28) - - +## [1.2.19](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.5...@aws-amplify/auth@1.2.19) (2019-03-28) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.19-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.4...@aws-amplify/auth@1.2.19-unstable.5) (2019-03-28) +## [1.2.19-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.4...@aws-amplify/auth@1.2.19-unstable.5) (2019-03-28) ### Features -* **core:** Hub refactor and tests ([7ac5bcf](https://github.com/aws/aws-amplify/commit/7ac5bcf)) - - - +- **core:** Hub refactor and tests ([7ac5bcf](https://github.com/aws/aws-amplify/commit/7ac5bcf)) -## [1.2.19-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.3...@aws-amplify/auth@1.2.19-unstable.4) (2019-03-24) +## [1.2.19-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.3...@aws-amplify/auth@1.2.19-unstable.4) (2019-03-24) ### Bug Fixes -* **auth:** Remove react-native related peerDependencies ([#2871](https://github.com/aws/aws-amplify/issues/2871)) ([72f3d94](https://github.com/aws/aws-amplify/commit/72f3d94)) - - - +- **auth:** Remove react-native related peerDependencies ([#2871](https://github.com/aws/aws-amplify/issues/2871)) ([72f3d94](https://github.com/aws/aws-amplify/commit/72f3d94)) -## [1.2.19-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.2...@aws-amplify/auth@1.2.19-unstable.3) (2019-03-22) +## [1.2.19-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.2...@aws-amplify/auth@1.2.19-unstable.3) (2019-03-22) ### Bug Fixes -* **@aws-amplify/auth:** get the user attributes after signing in ([c024263](https://github.com/aws/aws-amplify/commit/c024263)) - - - +- **@aws-amplify/auth:** get the user attributes after signing in ([c024263](https://github.com/aws/aws-amplify/commit/c024263)) -## [1.2.19-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.1...@aws-amplify/auth@1.2.19-unstable.2) (2019-03-22) - - +## [1.2.19-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.1...@aws-amplify/auth@1.2.19-unstable.2) (2019-03-22) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.19-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.0...@aws-amplify/auth@1.2.19-unstable.1) (2019-03-19) +## [1.2.19-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.19-unstable.0...@aws-amplify/auth@1.2.19-unstable.1) (2019-03-19) ### Bug Fixes -* **@aws-amplify/auth:** check if has the right scope to send the request GetUserData ([20bd92b](https://github.com/aws/aws-amplify/commit/20bd92b)) - - - +- **@aws-amplify/auth:** check if has the right scope to send the request GetUserData ([20bd92b](https://github.com/aws/aws-amplify/commit/20bd92b)) -## [1.2.19-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.18...@aws-amplify/auth@1.2.19-unstable.0) (2019-03-18) - - +## [1.2.19-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.18...@aws-amplify/auth@1.2.19-unstable.0) (2019-03-18) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.18](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.18-unstable.1...@aws-amplify/auth@1.2.18) (2019-03-06) - - +## [1.2.18](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.18-unstable.1...@aws-amplify/auth@1.2.18) (2019-03-06) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.18-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.18-unstable.0...@aws-amplify/auth@1.2.18-unstable.1) (2019-03-06) +## [1.2.18-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.18-unstable.0...@aws-amplify/auth@1.2.18-unstable.1) (2019-03-06) ### Bug Fixes -* **auth:** Split urlListener into web/react-native ([b33fee0](https://github.com/aws/aws-amplify/commit/b33fee0)), closes [#2808](https://github.com/aws/aws-amplify/issues/2808) - - - +- **auth:** Split urlListener into web/react-native ([b33fee0](https://github.com/aws/aws-amplify/commit/b33fee0)), closes [#2808](https://github.com/aws/aws-amplify/issues/2808) -## [1.2.18-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.17...@aws-amplify/auth@1.2.18-unstable.0) (2019-03-04) - - +## [1.2.18-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.17...@aws-amplify/auth@1.2.18-unstable.0) (2019-03-04) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.17](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16...@aws-amplify/auth@1.2.17) (2019-03-04) - - +## [1.2.17](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16...@aws-amplify/auth@1.2.17) (2019-03-04) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.16](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.8...@aws-amplify/auth@1.2.16) (2019-03-04) - - +## [1.2.16](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.8...@aws-amplify/auth@1.2.16) (2019-03-04) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.16-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.7...@aws-amplify/auth@1.2.16-unstable.8) (2019-03-04) +## [1.2.16-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.7...@aws-amplify/auth@1.2.16-unstable.8) (2019-03-04) ### Features -* **aws-amplify-react-native:** Add withOAuth HOC for Cognito Hosted UI ([#2665](https://github.com/aws/aws-amplify/issues/2665)) ([ac4d232](https://github.com/aws/aws-amplify/commit/ac4d232)) - - - +- **aws-amplify-react-native:** Add withOAuth HOC for Cognito Hosted UI ([#2665](https://github.com/aws/aws-amplify/issues/2665)) ([ac4d232](https://github.com/aws/aws-amplify/commit/ac4d232)) -## [1.2.16-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.6...@aws-amplify/auth@1.2.16-unstable.7) (2019-03-04) - - +## [1.2.16-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.6...@aws-amplify/auth@1.2.16-unstable.7) (2019-03-04) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.16-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.5...@aws-amplify/auth@1.2.16-unstable.6) (2019-03-01) - - +## [1.2.16-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.5...@aws-amplify/auth@1.2.16-unstable.6) (2019-03-01) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.16-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.4...@aws-amplify/auth@1.2.16-unstable.5) (2019-02-27) - - +## [1.2.16-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.4...@aws-amplify/auth@1.2.16-unstable.5) (2019-02-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.16-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.3...@aws-amplify/auth@1.2.16-unstable.4) (2019-02-27) - - +## [1.2.16-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.3...@aws-amplify/auth@1.2.16-unstable.4) (2019-02-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.16-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.2...@aws-amplify/auth@1.2.16-unstable.3) (2019-01-21) - - +## [1.2.16-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.2...@aws-amplify/auth@1.2.16-unstable.3) (2019-01-21) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.16-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.1...@aws-amplify/auth@1.2.16-unstable.2) (2019-01-18) - - +## [1.2.16-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.1...@aws-amplify/auth@1.2.16-unstable.2) (2019-01-18) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.16-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.0...@aws-amplify/auth@1.2.16-unstable.1) (2019-01-10) - - +## [1.2.16-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.16-unstable.0...@aws-amplify/auth@1.2.16-unstable.1) (2019-01-10) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.16-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.15...@aws-amplify/auth@1.2.16-unstable.0) (2019-01-10) - - +## [1.2.16-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.15...@aws-amplify/auth@1.2.16-unstable.0) (2019-01-10) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.15-unstable.0...@aws-amplify/auth@1.2.15) (2019-01-10) +## [1.2.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.15-unstable.0...@aws-amplify/auth@1.2.15) (2019-01-10) ### Bug Fixes -* **@aws-amplify/auth:** wait for cached data loaded into memory before calling getItem ([5fc6d77](https://github.com/aws/aws-amplify/commit/5fc6d77)) - - - +- **@aws-amplify/auth:** wait for cached data loaded into memory before calling getItem ([5fc6d77](https://github.com/aws/aws-amplify/commit/5fc6d77)) -## [1.2.15-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.14...@aws-amplify/auth@1.2.15-unstable.0) (2018-12-26) - - +## [1.2.15-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.14...@aws-amplify/auth@1.2.15-unstable.0) (2018-12-26) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.14-unstable.2...@aws-amplify/auth@1.2.14) (2018-12-26) - - +## [1.2.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.14-unstable.2...@aws-amplify/auth@1.2.14) (2018-12-26) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.14-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.14-unstable.1...@aws-amplify/auth@1.2.14-unstable.2) (2018-12-22) - - +## [1.2.14-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.14-unstable.1...@aws-amplify/auth@1.2.14-unstable.2) (2018-12-22) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.14-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.14-unstable.0...@aws-amplify/auth@1.2.14-unstable.1) (2018-12-20) +## [1.2.14-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.14-unstable.0...@aws-amplify/auth@1.2.14-unstable.1) (2018-12-20) ### Bug Fixes -* **@aws-amplify/auth:** typo ([2f411ad](https://github.com/aws/aws-amplify/commit/2f411ad)) - - - +- **@aws-amplify/auth:** typo ([2f411ad](https://github.com/aws/aws-amplify/commit/2f411ad)) -## [1.2.14-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.13...@aws-amplify/auth@1.2.14-unstable.0) (2018-12-19) +## [1.2.14-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.13...@aws-amplify/auth@1.2.14-unstable.0) (2018-12-19) ### Bug Fixes -* **@aws-amplify/auth:** put warning message in the federatedSignIn method ([9fff76a](https://github.com/aws/aws-amplify/commit/9fff76a)) - - - +- **@aws-amplify/auth:** put warning message in the federatedSignIn method ([9fff76a](https://github.com/aws/aws-amplify/commit/9fff76a)) -## [1.2.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.13-unstable.3...@aws-amplify/auth@1.2.13) (2018-12-13) - - +## [1.2.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.13-unstable.3...@aws-amplify/auth@1.2.13) (2018-12-13) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.13-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.13-unstable.2...@aws-amplify/auth@1.2.13-unstable.3) (2018-12-13) +## [1.2.13-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.13-unstable.2...@aws-amplify/auth@1.2.13-unstable.3) (2018-12-13) ### Features -* **@aws-amplify/auth:** add the option to pass validation data when signing in ([13093e9](https://github.com/aws/aws-amplify/commit/13093e9)) - - - +- **@aws-amplify/auth:** add the option to pass validation data when signing in ([13093e9](https://github.com/aws/aws-amplify/commit/13093e9)) -## [1.2.13-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.13-unstable.1...@aws-amplify/auth@1.2.13-unstable.2) (2018-12-13) - - +## [1.2.13-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.13-unstable.1...@aws-amplify/auth@1.2.13-unstable.2) (2018-12-13) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.13-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.13-unstable.0...@aws-amplify/auth@1.2.13-unstable.1) (2018-12-07) - - +## [1.2.13-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.13-unstable.0...@aws-amplify/auth@1.2.13-unstable.1) (2018-12-07) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.13-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.12...@aws-amplify/auth@1.2.13-unstable.0) (2018-12-07) - - +## [1.2.13-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.12...@aws-amplify/auth@1.2.13-unstable.0) (2018-12-07) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11...@aws-amplify/auth@1.2.12) (2018-12-07) - - +## [1.2.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11...@aws-amplify/auth@1.2.12) (2018-12-07) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.12-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11...@aws-amplify/auth@1.2.12-unstable.0) (2018-12-07) +## [1.2.12-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11...@aws-amplify/auth@1.2.12-unstable.0) (2018-12-07) ### Features -* **amazon-cognito-identity-js:** cache the user data ([f4dd225](https://github.com/aws/aws-amplify/commit/f4dd225)) - - - +- **amazon-cognito-identity-js:** cache the user data ([f4dd225](https://github.com/aws/aws-amplify/commit/f4dd225)) -## [1.2.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.10...@aws-amplify/auth@1.2.11) (2018-12-03) - - +## [1.2.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.10...@aws-amplify/auth@1.2.11) (2018-12-03) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.11-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.9...@aws-amplify/auth@1.2.11-unstable.10) (2018-11-27) - - +## [1.2.11-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.9...@aws-amplify/auth@1.2.11-unstable.10) (2018-11-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.11-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.8...@aws-amplify/auth@1.2.11-unstable.9) (2018-11-26) - - +## [1.2.11-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.8...@aws-amplify/auth@1.2.11-unstable.9) (2018-11-26) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.11-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.7...@aws-amplify/auth@1.2.11-unstable.8) (2018-11-20) - - +## [1.2.11-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.7...@aws-amplify/auth@1.2.11-unstable.8) (2018-11-20) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.11-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.6...@aws-amplify/auth@1.2.11-unstable.7) (2018-11-19) - - +## [1.2.11-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.6...@aws-amplify/auth@1.2.11-unstable.7) (2018-11-19) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.11-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.5...@aws-amplify/auth@1.2.11-unstable.6) (2018-11-19) - - +## [1.2.11-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.5...@aws-amplify/auth@1.2.11-unstable.6) (2018-11-19) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.11-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.4...@aws-amplify/auth@1.2.11-unstable.5) (2018-11-19) - - +## [1.2.11-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.4...@aws-amplify/auth@1.2.11-unstable.5) (2018-11-19) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.11-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.3...@aws-amplify/auth@1.2.11-unstable.4) (2018-11-17) - - +## [1.2.11-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.3...@aws-amplify/auth@1.2.11-unstable.4) (2018-11-17) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.11-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.2...@aws-amplify/auth@1.2.11-unstable.3) (2018-11-16) - - +## [1.2.11-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.2...@aws-amplify/auth@1.2.11-unstable.3) (2018-11-16) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.11-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.1...@aws-amplify/auth@1.2.11-unstable.2) (2018-11-16) - - +## [1.2.11-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.1...@aws-amplify/auth@1.2.11-unstable.2) (2018-11-16) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.11-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.0...@aws-amplify/auth@1.2.11-unstable.1) (2018-11-15) - - +## [1.2.11-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.11-unstable.0...@aws-amplify/auth@1.2.11-unstable.1) (2018-11-15) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.11-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.10...@aws-amplify/auth@1.2.11-unstable.0) (2018-11-13) - - +## [1.2.11-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.10...@aws-amplify/auth@1.2.11-unstable.0) (2018-11-13) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.10-unstable.1...@aws-amplify/auth@1.2.10) (2018-11-12) - - +## [1.2.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.10-unstable.1...@aws-amplify/auth@1.2.10) (2018-11-12) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.10-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.10-unstable.0...@aws-amplify/auth@1.2.10-unstable.1) (2018-11-09) +## [1.2.10-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.10-unstable.0...@aws-amplify/auth@1.2.10-unstable.1) (2018-11-09) ### Features -* **aws-amplify-react:** adding loading page ([c47f72a](https://github.com/aws/aws-amplify/commit/c47f72a)) - - - +- **aws-amplify-react:** adding loading page ([c47f72a](https://github.com/aws/aws-amplify/commit/c47f72a)) -## [1.2.10-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.9...@aws-amplify/auth@1.2.10-unstable.0) (2018-11-06) - - +## [1.2.10-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.9...@aws-amplify/auth@1.2.10-unstable.0) (2018-11-06) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.9-unstable.0...@aws-amplify/auth@1.2.9) (2018-11-01) - - +## [1.2.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.9-unstable.0...@aws-amplify/auth@1.2.9) (2018-11-01) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.9-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.8...@aws-amplify/auth@1.2.9-unstable.0) (2018-10-30) - - +## [1.2.9-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.8...@aws-amplify/auth@1.2.9-unstable.0) (2018-10-30) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.8-unstable.1...@aws-amplify/auth@1.2.8) (2018-10-29) - - +## [1.2.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.8-unstable.1...@aws-amplify/auth@1.2.8) (2018-10-29) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.8-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.8-unstable.0...@aws-amplify/auth@1.2.8-unstable.1) (2018-10-29) - - +## [1.2.8-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.8-unstable.0...@aws-amplify/auth@1.2.8-unstable.1) (2018-10-29) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.8-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.7...@aws-amplify/auth@1.2.8-unstable.0) (2018-10-29) - - +## [1.2.8-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.7...@aws-amplify/auth@1.2.8-unstable.0) (2018-10-29) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.7-unstable.3...@aws-amplify/auth@1.2.7) (2018-10-17) - - +## [1.2.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.7-unstable.3...@aws-amplify/auth@1.2.7) (2018-10-17) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.7-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.7-unstable.2...@aws-amplify/auth@1.2.7-unstable.3) (2018-10-16) - - +## [1.2.7-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.7-unstable.2...@aws-amplify/auth@1.2.7-unstable.3) (2018-10-16) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.7-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.7-unstable.1...@aws-amplify/auth@1.2.7-unstable.2) (2018-10-08) +## [1.2.7-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.7-unstable.1...@aws-amplify/auth@1.2.7-unstable.2) (2018-10-08) ### Bug Fixes -* **@aws-amplify/auth:** throw error when failed to sync items from AsyncStorage into Memory ([85c3f32](https://github.com/aws/aws-amplify/commit/85c3f32)) - - - +- **@aws-amplify/auth:** throw error when failed to sync items from AsyncStorage into Memory ([85c3f32](https://github.com/aws/aws-amplify/commit/85c3f32)) -## [1.2.7-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.7-unstable.0...@aws-amplify/auth@1.2.7-unstable.1) (2018-10-05) - - +## [1.2.7-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.7-unstable.0...@aws-amplify/auth@1.2.7-unstable.1) (2018-10-05) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.7-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.6-unstable.1...@aws-amplify/auth@1.2.7-unstable.0) (2018-10-05) - - +## [1.2.7-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.6-unstable.1...@aws-amplify/auth@1.2.7-unstable.0) (2018-10-05) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.6-unstable.1...@aws-amplify/auth@1.2.6) (2018-10-04) - - +## [1.2.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.6-unstable.1...@aws-amplify/auth@1.2.6) (2018-10-04) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.6-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.6-unstable.0...@aws-amplify/auth@1.2.6-unstable.1) (2018-10-03) - - +## [1.2.6-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.6-unstable.0...@aws-amplify/auth@1.2.6-unstable.1) (2018-10-03) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.6-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.4...@aws-amplify/auth@1.2.6-unstable.0) (2018-10-03) - - +## [1.2.6-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.4...@aws-amplify/auth@1.2.6-unstable.0) (2018-10-03) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.4...@aws-amplify/auth@1.2.5) (2018-10-03) - - +## [1.2.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.4...@aws-amplify/auth@1.2.5) (2018-10-03) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.5-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.3...@aws-amplify/auth@1.2.5-unstable.4) (2018-10-01) - - +## [1.2.5-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.3...@aws-amplify/auth@1.2.5-unstable.4) (2018-10-01) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.5-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.2...@aws-amplify/auth@1.2.5-unstable.3) (2018-09-28) - - +## [1.2.5-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.2...@aws-amplify/auth@1.2.5-unstable.3) (2018-09-28) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.5-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.1...@aws-amplify/auth@1.2.5-unstable.2) (2018-09-27) - - +## [1.2.5-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.1...@aws-amplify/auth@1.2.5-unstable.2) (2018-09-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.5-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.0...@aws-amplify/auth@1.2.5-unstable.1) (2018-09-27) - - +## [1.2.5-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.5-unstable.0...@aws-amplify/auth@1.2.5-unstable.1) (2018-09-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.5-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4...@aws-amplify/auth@1.2.5-unstable.0) (2018-09-27) - - +## [1.2.5-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4...@aws-amplify/auth@1.2.5-unstable.0) (2018-09-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.9...@aws-amplify/auth@1.2.4) (2018-09-27) - - +## [1.2.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.9...@aws-amplify/auth@1.2.4) (2018-09-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.4-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.8...@aws-amplify/auth@1.2.4-unstable.9) (2018-09-26) - - +## [1.2.4-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.8...@aws-amplify/auth@1.2.4-unstable.9) (2018-09-26) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.4-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.7...@aws-amplify/auth@1.2.4-unstable.8) (2018-09-26) - - +## [1.2.4-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.7...@aws-amplify/auth@1.2.4-unstable.8) (2018-09-26) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.4-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.6...@aws-amplify/auth@1.2.4-unstable.7) (2018-09-26) - - +## [1.2.4-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.6...@aws-amplify/auth@1.2.4-unstable.7) (2018-09-26) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.4-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.4...@aws-amplify/auth@1.2.4-unstable.6) (2018-09-26) - - +## [1.2.4-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.4...@aws-amplify/auth@1.2.4-unstable.6) (2018-09-26) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.4-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.4...@aws-amplify/auth@1.2.4-unstable.5) (2018-09-25) - - +## [1.2.4-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.4...@aws-amplify/auth@1.2.4-unstable.5) (2018-09-25) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.4-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.3...@aws-amplify/auth@1.2.4-unstable.4) (2018-09-25) - - +## [1.2.4-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.3...@aws-amplify/auth@1.2.4-unstable.4) (2018-09-25) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.4-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.2...@aws-amplify/auth@1.2.4-unstable.3) (2018-09-24) - - +## [1.2.4-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.2...@aws-amplify/auth@1.2.4-unstable.3) (2018-09-24) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.4-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.1...@aws-amplify/auth@1.2.4-unstable.2) (2018-09-22) - - +## [1.2.4-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.1...@aws-amplify/auth@1.2.4-unstable.2) (2018-09-22) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.4-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.0...@aws-amplify/auth@1.2.4-unstable.1) (2018-09-22) - - +## [1.2.4-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.4-unstable.0...@aws-amplify/auth@1.2.4-unstable.1) (2018-09-22) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.4-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.3...@aws-amplify/auth@1.2.4-unstable.0) (2018-09-22) - - +## [1.2.4-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.3...@aws-amplify/auth@1.2.4-unstable.0) (2018-09-22) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.3-unstable.0...@aws-amplify/auth@1.2.3) (2018-09-21) +## [1.2.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.3-unstable.0...@aws-amplify/auth@1.2.3) (2018-09-21) ### Bug Fixes -* **@aws-amplify/auth:** fix typescript declaration for backward compatibility ([f43bbf4](https://github.com/aws/aws-amplify/commit/f43bbf4)) - - - +- **@aws-amplify/auth:** fix typescript declaration for backward compatibility ([f43bbf4](https://github.com/aws/aws-amplify/commit/f43bbf4)) -## [1.2.3-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.2-unstable.3...@aws-amplify/auth@1.2.3-unstable.0) (2018-09-21) +## [1.2.3-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.2-unstable.3...@aws-amplify/auth@1.2.3-unstable.0) (2018-09-21) ### Bug Fixes -* bumping version for deploying on unstable tag ([#1706](https://github.com/aws/aws-amplify/issues/1706)) ([b5d6468](https://github.com/aws/aws-amplify/commit/b5d6468)) - - - +- bumping version for deploying on unstable tag ([#1706](https://github.com/aws/aws-amplify/issues/1706)) ([b5d6468](https://github.com/aws/aws-amplify/commit/b5d6468)) -## [1.2.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.1...@aws-amplify/auth@1.2.2) (2018-09-21) - - +## [1.2.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.1...@aws-amplify/auth@1.2.2) (2018-09-21) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.2-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.2-unstable.2...@aws-amplify/auth@1.2.2-unstable.3) (2018-09-20) - - +## [1.2.2-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.2-unstable.2...@aws-amplify/auth@1.2.2-unstable.3) (2018-09-20) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.2-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.2-unstable.1...@aws-amplify/auth@1.2.2-unstable.2) (2018-09-20) - - +## [1.2.2-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.2-unstable.1...@aws-amplify/auth@1.2.2-unstable.2) (2018-09-20) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.2-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.2-unstable.0...@aws-amplify/auth@1.2.2-unstable.1) (2018-09-17) - - +## [1.2.2-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.2-unstable.0...@aws-amplify/auth@1.2.2-unstable.1) (2018-09-17) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.1...@aws-amplify/auth@1.2.2-unstable.0) (2018-09-17) - - +## [1.2.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.2.1...@aws-amplify/auth@1.2.2-unstable.0) (2018-09-17) **Note:** Version bump only for package @aws-amplify/auth -## [1.2.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.1.2...@aws-amplify/auth@1.2.1) (2018-09-17) +## [1.2.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.1.2...@aws-amplify/auth@1.2.1) (2018-09-17) ### Bug Fixes -* **@aws-amplify/auth:** add typescript declartions to Auth ([6f02a18](https://github.com/aws/aws-amplify/commit/6f02a18)) - - - +- **@aws-amplify/auth:** add typescript declartions to Auth ([6f02a18](https://github.com/aws/aws-amplify/commit/6f02a18)) -## [1.1.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.1.1...@aws-amplify/auth@1.1.2) (2018-09-12) - - +## [1.1.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.1.1...@aws-amplify/auth@1.1.2) (2018-09-12) **Note:** Version bump only for package @aws-amplify/auth -## [1.1.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.1.1-unstable.0...@aws-amplify/auth@1.1.1) (2018-09-09) - - +## [1.1.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.1.1-unstable.0...@aws-amplify/auth@1.1.1) (2018-09-09) **Note:** Version bump only for package @aws-amplify/auth -## [1.1.1-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.1.0...@aws-amplify/auth@1.1.1-unstable.0) (2018-09-09) - - +## [1.1.1-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.1.0...@aws-amplify/auth@1.1.1-unstable.0) (2018-09-09) **Note:** Version bump only for package @aws-amplify/auth -# [1.1.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.9-unstable.4...@aws-amplify/auth@1.1.0) (2018-09-09) - - +# [1.1.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.9-unstable.4...@aws-amplify/auth@1.1.0) (2018-09-09) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.9-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.9-unstable.3...@aws-amplify/auth@1.0.9-unstable.4) (2018-09-07) - - +## [1.0.9-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.9-unstable.3...@aws-amplify/auth@1.0.9-unstable.4) (2018-09-07) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.9-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.9-unstable.2...@aws-amplify/auth@1.0.9-unstable.3) (2018-09-06) +## [1.0.9-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.9-unstable.2...@aws-amplify/auth@1.0.9-unstable.3) (2018-09-06) ### Features -* **@aws-amplify/auth:** allow globalSignOut ([b8b24c7](https://github.com/aws/aws-amplify/commit/b8b24c7)) - - - +- **@aws-amplify/auth:** allow globalSignOut ([b8b24c7](https://github.com/aws/aws-amplify/commit/b8b24c7)) -## [1.0.9-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.8...@aws-amplify/auth@1.0.9-unstable.2) (2018-08-31) +## [1.0.9-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.8...@aws-amplify/auth@1.0.9-unstable.2) (2018-08-31) ### Bug Fixes -* **@aws-amplify/auth:** allow return sub attribute to user ([fc48010](https://github.com/aws/aws-amplify/commit/fc48010)) -* **@aws-amplify/auth:** correctly throw the error when the refresh token is expired ([c61505a](https://github.com/aws/aws-amplify/commit/c61505a)) - - - +- **@aws-amplify/auth:** allow return sub attribute to user ([fc48010](https://github.com/aws/aws-amplify/commit/fc48010)) +- **@aws-amplify/auth:** correctly throw the error when the refresh token is expired ([c61505a](https://github.com/aws/aws-amplify/commit/c61505a)) -## [1.0.9-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.8...@aws-amplify/auth@1.0.9-unstable.1) (2018-08-30) +## [1.0.9-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.8...@aws-amplify/auth@1.0.9-unstable.1) (2018-08-30) ### Bug Fixes -* **@aws-amplify/auth:** correctly throw the error when the refresh token is expired ([c61505a](https://github.com/aws/aws-amplify/commit/c61505a)) - - - +- **@aws-amplify/auth:** correctly throw the error when the refresh token is expired ([c61505a](https://github.com/aws/aws-amplify/commit/c61505a)) -## [1.0.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.26...@aws-amplify/auth@1.0.8) (2018-08-28) - - +## [1.0.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.26...@aws-amplify/auth@1.0.8) (2018-08-28) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.26](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.25...@aws-amplify/auth@1.0.7-unstable.26) (2018-08-28) - - +## [1.0.7-unstable.26](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.25...@aws-amplify/auth@1.0.7-unstable.26) (2018-08-28) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.25](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.24...@aws-amplify/auth@1.0.7-unstable.25) (2018-08-27) - - +## [1.0.7-unstable.25](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.24...@aws-amplify/auth@1.0.7-unstable.25) (2018-08-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.24](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.23...@aws-amplify/auth@1.0.7-unstable.24) (2018-08-27) - - +## [1.0.7-unstable.24](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.23...@aws-amplify/auth@1.0.7-unstable.24) (2018-08-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.23](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.21...@aws-amplify/auth@1.0.7-unstable.23) (2018-08-27) - - +## [1.0.7-unstable.23](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.21...@aws-amplify/auth@1.0.7-unstable.23) (2018-08-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.22](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.21...@aws-amplify/auth@1.0.7-unstable.22) (2018-08-25) - - +## [1.0.7-unstable.22](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.21...@aws-amplify/auth@1.0.7-unstable.22) (2018-08-25) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.21](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.20...@aws-amplify/auth@1.0.7-unstable.21) (2018-08-24) - - +## [1.0.7-unstable.21](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.20...@aws-amplify/auth@1.0.7-unstable.21) (2018-08-24) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.20](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.19...@aws-amplify/auth@1.0.7-unstable.20) (2018-08-24) - - +## [1.0.7-unstable.20](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.19...@aws-amplify/auth@1.0.7-unstable.20) (2018-08-24) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.19](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.17...@aws-amplify/auth@1.0.7-unstable.19) (2018-08-24) - - +## [1.0.7-unstable.19](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.17...@aws-amplify/auth@1.0.7-unstable.19) (2018-08-24) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.18](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.17...@aws-amplify/auth@1.0.7-unstable.18) (2018-08-24) - - +## [1.0.7-unstable.18](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.17...@aws-amplify/auth@1.0.7-unstable.18) (2018-08-24) **Note:** Version bump only for package @aws-amplify/auth - -## [1.0.7-unstable.17](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.15...@aws-amplify/auth@1.0.7-unstable.17) (2018-08-24) - - + +## [1.0.7-unstable.17](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.15...@aws-amplify/auth@1.0.7-unstable.17) (2018-08-24) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.16](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.15...@aws-amplify/auth@1.0.7-unstable.16) (2018-08-24) - - +## [1.0.7-unstable.16](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.15...@aws-amplify/auth@1.0.7-unstable.16) (2018-08-24) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.14...@aws-amplify/auth@1.0.7-unstable.15) (2018-08-24) - - +## [1.0.7-unstable.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.14...@aws-amplify/auth@1.0.7-unstable.15) (2018-08-24) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.13...@aws-amplify/auth@1.0.7-unstable.14) (2018-08-24) - - +## [1.0.7-unstable.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.13...@aws-amplify/auth@1.0.7-unstable.14) (2018-08-24) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.11...@aws-amplify/auth@1.0.7-unstable.13) (2018-08-23) - - +## [1.0.7-unstable.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.11...@aws-amplify/auth@1.0.7-unstable.13) (2018-08-23) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.11...@aws-amplify/auth@1.0.7-unstable.12) (2018-08-23) - - +## [1.0.7-unstable.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.11...@aws-amplify/auth@1.0.7-unstable.12) (2018-08-23) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.10...@aws-amplify/auth@1.0.7-unstable.11) (2018-08-23) - - +## [1.0.7-unstable.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.10...@aws-amplify/auth@1.0.7-unstable.11) (2018-08-23) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.9...@aws-amplify/auth@1.0.7-unstable.10) (2018-08-23) - - +## [1.0.7-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.9...@aws-amplify/auth@1.0.7-unstable.10) (2018-08-23) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.8...@aws-amplify/auth@1.0.7-unstable.9) (2018-08-23) - - +## [1.0.7-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.8...@aws-amplify/auth@1.0.7-unstable.9) (2018-08-23) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.7...@aws-amplify/auth@1.0.7-unstable.8) (2018-08-22) - - +## [1.0.7-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.7...@aws-amplify/auth@1.0.7-unstable.8) (2018-08-22) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.6...@aws-amplify/auth@1.0.7-unstable.7) (2018-08-22) - - +## [1.0.7-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.6...@aws-amplify/auth@1.0.7-unstable.7) (2018-08-22) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.5...@aws-amplify/auth@1.0.7-unstable.6) (2018-08-21) +## [1.0.7-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.5...@aws-amplify/auth@1.0.7-unstable.6) (2018-08-21) ### Bug Fixes -* **@aws-amplify/auth:** check if window object exists for browser usage ([17d6a3d](https://github.com/aws/aws-amplify/commit/17d6a3d)) - - - +- **@aws-amplify/auth:** check if window object exists for browser usage ([17d6a3d](https://github.com/aws/aws-amplify/commit/17d6a3d)) -## [1.0.7-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.4...@aws-amplify/auth@1.0.7-unstable.5) (2018-08-21) - - +## [1.0.7-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.4...@aws-amplify/auth@1.0.7-unstable.5) (2018-08-21) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.3...@aws-amplify/auth@1.0.7-unstable.4) (2018-08-20) - - +## [1.0.7-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.3...@aws-amplify/auth@1.0.7-unstable.4) (2018-08-20) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.2...@aws-amplify/auth@1.0.7-unstable.3) (2018-08-19) +## [1.0.7-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.2...@aws-amplify/auth@1.0.7-unstable.3) (2018-08-19) ### Bug Fixes -* **aws-amplify-angular:** Angular rollup ([#1441](https://github.com/aws/aws-amplify/issues/1441)) ([eb84e01](https://github.com/aws/aws-amplify/commit/eb84e01)) - - - +- **aws-amplify-angular:** Angular rollup ([#1441](https://github.com/aws/aws-amplify/issues/1441)) ([eb84e01](https://github.com/aws/aws-amplify/commit/eb84e01)) -## [1.0.7-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.1...@aws-amplify/auth@1.0.7-unstable.2) (2018-08-18) - - +## [1.0.7-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.1...@aws-amplify/auth@1.0.7-unstable.2) (2018-08-18) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.0...@aws-amplify/auth@1.0.7-unstable.1) (2018-08-16) - - +## [1.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.7-unstable.0...@aws-amplify/auth@1.0.7-unstable.1) (2018-08-16) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6...@aws-amplify/auth@1.0.7-unstable.0) (2018-08-15) - - +## [1.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6...@aws-amplify/auth@1.0.7-unstable.0) (2018-08-15) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.5...@aws-amplify/auth@1.0.6) (2018-08-14) - - +## [1.0.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.5...@aws-amplify/auth@1.0.6) (2018-08-14) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.6-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.4...@aws-amplify/auth@1.0.6-unstable.5) (2018-08-14) - - +## [1.0.6-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.4...@aws-amplify/auth@1.0.6-unstable.5) (2018-08-14) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.6-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.3...@aws-amplify/auth@1.0.6-unstable.4) (2018-08-13) +## [1.0.6-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.3...@aws-amplify/auth@1.0.6-unstable.4) (2018-08-13) ### Bug Fixes -* **@aws-amplify/auth:** dispatching failure event when hosted UI and documentation enhancement for hosted UI ([b13e937](https://github.com/aws/aws-amplify/commit/b13e937)) - - - +- **@aws-amplify/auth:** dispatching failure event when hosted UI and documentation enhancement for hosted UI ([b13e937](https://github.com/aws/aws-amplify/commit/b13e937)) -## [1.0.6-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.2...@aws-amplify/auth@1.0.6-unstable.3) (2018-08-13) - - +## [1.0.6-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.2...@aws-amplify/auth@1.0.6-unstable.3) (2018-08-13) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.1...@aws-amplify/auth@1.0.6-unstable.2) (2018-08-09) - - +## [1.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.1...@aws-amplify/auth@1.0.6-unstable.2) (2018-08-09) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.0...@aws-amplify/auth@1.0.6-unstable.1) (2018-08-07) - - +## [1.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.6-unstable.0...@aws-amplify/auth@1.0.6-unstable.1) (2018-08-07) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5...@aws-amplify/auth@1.0.6-unstable.0) (2018-08-07) - - +## [1.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5...@aws-amplify/auth@1.0.6-unstable.0) (2018-08-07) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.7...@aws-amplify/auth@1.0.5) (2018-08-06) - - +## [1.0.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.7...@aws-amplify/auth@1.0.5) (2018-08-06) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.5-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.6...@aws-amplify/auth@1.0.5-unstable.7) (2018-08-06) - - +## [1.0.5-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.6...@aws-amplify/auth@1.0.5-unstable.7) (2018-08-06) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.5-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.5...@aws-amplify/auth@1.0.5-unstable.6) (2018-08-06) +## [1.0.5-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.5...@aws-amplify/auth@1.0.5-unstable.6) (2018-08-06) ### Bug Fixes -* **@aws-amplify/auth:** for currentUserPoolUser, only throws error when the user is disabled or deleted ([a800747](https://github.com/aws/aws-amplify/commit/a800747)) - - - +- **@aws-amplify/auth:** for currentUserPoolUser, only throws error when the user is disabled or deleted ([a800747](https://github.com/aws/aws-amplify/commit/a800747)) -## [1.0.5-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.3...@aws-amplify/auth@1.0.5-unstable.5) (2018-08-06) +## [1.0.5-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.3...@aws-amplify/auth@1.0.5-unstable.5) (2018-08-06) ### Bug Fixes -* **@aws-amplify/auth:** fix getPreferredMfa and setPreferredMFA ([c5785b0](https://github.com/aws/aws-amplify/commit/c5785b0)) - - - +- **@aws-amplify/auth:** fix getPreferredMfa and setPreferredMFA ([c5785b0](https://github.com/aws/aws-amplify/commit/c5785b0)) -## [1.0.5-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.2...@aws-amplify/auth@1.0.5-unstable.3) (2018-07-31) - - +## [1.0.5-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.2...@aws-amplify/auth@1.0.5-unstable.3) (2018-07-31) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.5-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.1...@aws-amplify/auth@1.0.5-unstable.2) (2018-07-31) +## [1.0.5-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.1...@aws-amplify/auth@1.0.5-unstable.2) (2018-07-31) ### Bug Fixes -* **@aws-amplify/auth:** revert break changes in currentAuthenticatedUser ([7c806bd](https://github.com/aws/aws-amplify/commit/7c806bd)) - - - +- **@aws-amplify/auth:** revert break changes in currentAuthenticatedUser ([7c806bd](https://github.com/aws/aws-amplify/commit/7c806bd)) -## [1.0.5-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.0...@aws-amplify/auth@1.0.5-unstable.1) (2018-07-30) - - +## [1.0.5-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.5-unstable.0...@aws-amplify/auth@1.0.5-unstable.1) (2018-07-30) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.4...@aws-amplify/auth@1.0.5-unstable.0) (2018-07-30) - - +## [1.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.4...@aws-amplify/auth@1.0.5-unstable.0) (2018-07-30) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.4-unstable.1...@aws-amplify/auth@1.0.4) (2018-07-28) - - +## [1.0.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.4-unstable.1...@aws-amplify/auth@1.0.4) (2018-07-28) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.4-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.4-unstable.0...@aws-amplify/auth@1.0.4-unstable.1) (2018-07-28) - - +## [1.0.4-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.4-unstable.0...@aws-amplify/auth@1.0.4-unstable.1) (2018-07-28) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.14...@aws-amplify/auth@1.0.4-unstable.0) (2018-07-27) - - +## [1.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.14...@aws-amplify/auth@1.0.4-unstable.0) (2018-07-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.14...@aws-amplify/auth@1.0.3-unstable.15) (2018-07-27) - - +## [1.0.3-unstable.15](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.14...@aws-amplify/auth@1.0.3-unstable.15) (2018-07-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.13...@aws-amplify/auth@1.0.3-unstable.14) (2018-07-27) - - +## [1.0.3-unstable.14](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.13...@aws-amplify/auth@1.0.3-unstable.14) (2018-07-27) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.12...@aws-amplify/auth@1.0.3-unstable.13) (2018-07-26) - - +## [1.0.3-unstable.13](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.12...@aws-amplify/auth@1.0.3-unstable.13) (2018-07-26) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.11...@aws-amplify/auth@1.0.3-unstable.12) (2018-07-26) +## [1.0.3-unstable.12](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.11...@aws-amplify/auth@1.0.3-unstable.12) (2018-07-26) ### Bug Fixes -* **@aws-amplify/auth:** currentAuthenticatedUser throws error when the user is disabled/deleted ([1b09e2f](https://github.com/aws/aws-amplify/commit/1b09e2f)) - - - +- **@aws-amplify/auth:** currentAuthenticatedUser throws error when the user is disabled/deleted ([1b09e2f](https://github.com/aws/aws-amplify/commit/1b09e2f)) -## [1.0.3-unstable.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.10...@aws-amplify/auth@1.0.3-unstable.11) (2018-07-26) - - +## [1.0.3-unstable.11](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.10...@aws-amplify/auth@1.0.3-unstable.11) (2018-07-26) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.9...@aws-amplify/auth@1.0.3-unstable.10) (2018-07-26) - - +## [1.0.3-unstable.10](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.9...@aws-amplify/auth@1.0.3-unstable.10) (2018-07-26) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.8...@aws-amplify/auth@1.0.3-unstable.9) (2018-07-25) - - +## [1.0.3-unstable.9](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.8...@aws-amplify/auth@1.0.3-unstable.9) (2018-07-25) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.7...@aws-amplify/auth@1.0.3-unstable.8) (2018-07-25) - - +## [1.0.3-unstable.8](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.7...@aws-amplify/auth@1.0.3-unstable.8) (2018-07-25) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.6...@aws-amplify/auth@1.0.3-unstable.7) (2018-07-25) - - +## [1.0.3-unstable.7](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.6...@aws-amplify/auth@1.0.3-unstable.7) (2018-07-25) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.5...@aws-amplify/auth@1.0.3-unstable.6) (2018-07-24) - - +## [1.0.3-unstable.6](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.5...@aws-amplify/auth@1.0.3-unstable.6) (2018-07-24) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.4...@aws-amplify/auth@1.0.3-unstable.5) (2018-07-23) - - +## [1.0.3-unstable.5](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.4...@aws-amplify/auth@1.0.3-unstable.5) (2018-07-23) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.3...@aws-amplify/auth@1.0.3-unstable.4) (2018-07-23) - - +## [1.0.3-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.3...@aws-amplify/auth@1.0.3-unstable.4) (2018-07-23) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.2...@aws-amplify/auth@1.0.3-unstable.3) (2018-07-23) - - +## [1.0.3-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.2...@aws-amplify/auth@1.0.3-unstable.3) (2018-07-23) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.1...@aws-amplify/auth@1.0.3-unstable.2) (2018-07-20) +## [1.0.3-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.1...@aws-amplify/auth@1.0.3-unstable.2) (2018-07-20) ### Bug Fixes -* **@aws-amplify/auth:** give the option to set Federated Identity Pool region ([f370b33](https://github.com/aws/aws-amplify/commit/f370b33)) - - - +- **@aws-amplify/auth:** give the option to set Federated Identity Pool region ([f370b33](https://github.com/aws/aws-amplify/commit/f370b33)) -## [1.0.3-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.0...@aws-amplify/auth@1.0.3-unstable.1) (2018-07-20) - - +## [1.0.3-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.3-unstable.0...@aws-amplify/auth@1.0.3-unstable.1) (2018-07-20) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.2...@aws-amplify/auth@1.0.3-unstable.0) (2018-07-20) +## [1.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.2...@aws-amplify/auth@1.0.3-unstable.0) (2018-07-20) ### Bug Fixes -* **@aws-amplify/auth:** fix issue [#1165](https://github.com/aws/aws-amplify/issues/1165) and adds an api to get current preferred mfa type ([6f8a100](https://github.com/aws/aws-amplify/commit/6f8a100)) - - - +- **@aws-amplify/auth:** fix issue [#1165](https://github.com/aws/aws-amplify/issues/1165) and adds an api to get current preferred mfa type ([6f8a100](https://github.com/aws/aws-amplify/commit/6f8a100)) -## [1.0.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.2-unstable.1...@aws-amplify/auth@1.0.2) (2018-07-19) - - +## [1.0.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.2-unstable.1...@aws-amplify/auth@1.0.2) (2018-07-19) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.2-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1...@aws-amplify/auth@1.0.2-unstable.1) (2018-07-19) +## [1.0.2-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1...@aws-amplify/auth@1.0.2-unstable.1) (2018-07-19) ### Bug Fixes -* **@aws-amplify/auth:** add try cache for operations of auth storage ([96c100e](https://github.com/aws/aws-amplify/commit/96c100e)) -* **@aws-amplify/core:** add try cache for operations of auth storage ([2bf8364](https://github.com/aws/aws-amplify/commit/2bf8364)) - - - +- **@aws-amplify/auth:** add try cache for operations of auth storage ([96c100e](https://github.com/aws/aws-amplify/commit/96c100e)) +- **@aws-amplify/core:** add try cache for operations of auth storage ([2bf8364](https://github.com/aws/aws-amplify/commit/2bf8364)) -## [1.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1...@aws-amplify/auth@1.0.2-unstable.0) (2018-07-19) - - +## [1.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1...@aws-amplify/auth@1.0.2-unstable.0) (2018-07-19) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1-unstable.4...@aws-amplify/auth@1.0.1) (2018-07-18) - - +## [1.0.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1-unstable.4...@aws-amplify/auth@1.0.1) (2018-07-18) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.1-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1-unstable.3...@aws-amplify/auth@1.0.1-unstable.4) (2018-07-18) - - +## [1.0.1-unstable.4](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1-unstable.3...@aws-amplify/auth@1.0.1-unstable.4) (2018-07-18) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.1-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1-unstable.2...@aws-amplify/auth@1.0.1-unstable.3) (2018-07-18) - - +## [1.0.1-unstable.3](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1-unstable.2...@aws-amplify/auth@1.0.1-unstable.3) (2018-07-18) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1-unstable.1...@aws-amplify/auth@1.0.1-unstable.2) (2018-07-18) - - +## [1.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1-unstable.1...@aws-amplify/auth@1.0.1-unstable.2) (2018-07-18) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1...@aws-amplify/auth@1.0.1-unstable.1) (2018-07-18) - - +## [1.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1...@aws-amplify/auth@1.0.1-unstable.1) (2018-07-18) **Note:** Version bump only for package @aws-amplify/auth -## [1.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1...@aws-amplify/auth@1.0.1-unstable.0) (2018-07-18) - - +## [1.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/@aws-amplify/auth@1.0.1...@aws-amplify/auth@1.0.1-unstable.0) (2018-07-18) **Note:** Version bump only for package @aws-amplify/auth -## 0.1.1-unstable.0 (2018-06-27) - - +## 0.1.1-unstable.0 (2018-06-27) **Note:** Version bump only for package @aws-amplify/auth diff --git a/packages/auth/__tests__/auth-configure-test.ts b/packages/auth/__tests__/auth-configure-test.ts index 808c5c32c15..eb57efe70d7 100644 --- a/packages/auth/__tests__/auth-configure-test.ts +++ b/packages/auth/__tests__/auth-configure-test.ts @@ -1,21 +1,21 @@ import Auth from '../src/Auth'; describe('configure test', () => { - test.only('throw error when storage is empty', () => { - const opts = { - userPoolId: "awsUserPoolsId", - userPoolWebClientId: "awsUserPoolsWebClientId", - region: "region", - identityPoolId: "awsCognitoIdentityPoolId", - mandatorySignIn: false, - storage: {} - }; - const auth = new Auth(null); - expect.assertions(1); - try { - auth.configure(opts); - } catch (e) { - expect(e).not.toBeNull(); - } - }); - }); \ No newline at end of file + test.only('throw error when storage is empty', () => { + const opts = { + userPoolId: 'awsUserPoolsId', + userPoolWebClientId: 'awsUserPoolsWebClientId', + region: 'region', + identityPoolId: 'awsCognitoIdentityPoolId', + mandatorySignIn: false, + storage: {}, + }; + const auth = new Auth(null); + expect.assertions(1); + try { + auth.configure(opts); + } catch (e) { + expect(e).not.toBeNull(); + } + }); +}); diff --git a/packages/auth/__tests__/auth-unit-test.ts b/packages/auth/__tests__/auth-unit-test.ts index 40bfbd80a96..9de2f5bb5ee 100644 --- a/packages/auth/__tests__/auth-unit-test.ts +++ b/packages/auth/__tests__/auth-unit-test.ts @@ -1,2567 +1,2911 @@ - -import OAuth from '../src/OAuth/OAuth'; +import OAuth from '../src/OAuth/OAuth'; import * as oauthStorage from '../src/OAuth/oauthStorage'; jest.mock('../src/OAuth/oauthStorage', () => { - return { - clearAll: jest.fn(), - setState: jest.fn(), - setPKCE: jest.fn(), - getState: jest.fn(), - getPKCE: jest.fn() - }; + return { + clearAll: jest.fn(), + setState: jest.fn(), + setPKCE: jest.fn(), + getState: jest.fn(), + getPKCE: jest.fn(), + }; }); jest.mock('amazon-cognito-identity-js/lib/CognitoIdToken', () => { - const CognitoIdToken = () => {}; - - CognitoIdToken.prototype.CognitoIdToken = (value) => { - CognitoIdToken.prototype.idToken = value; - return CognitoIdToken; - }; + const CognitoIdToken = () => {}; - CognitoIdToken.prototype.getJwtToken = () => { - return 'jwtToken'; - }; + CognitoIdToken.prototype.CognitoIdToken = value => { + CognitoIdToken.prototype.idToken = value; + return CognitoIdToken; + }; + CognitoIdToken.prototype.getJwtToken = () => { + return 'jwtToken'; + }; - return CognitoIdToken; + return CognitoIdToken; }); jest.mock('amazon-cognito-identity-js/lib/CognitoUserSession', () => { - const CognitoUserSession = () => {}; - - CognitoUserSession.prototype.CognitoUserSession = (options) => { - CognitoUserSession.prototype.options = options; - return CognitoUserSession; - }; - - CognitoUserSession.prototype.getIdToken = () => { - return { - getJwtToken: () => { - return null; - } - }; - }; - - CognitoUserSession.prototype.getAccessToken = () => { - return 'accessToken'; - } - - CognitoUserSession.prototype.isValid = () => { - return true; - } - - CognitoUserSession.prototype.getRefreshToken = () => { - return 'refreshToken'; - } - - return CognitoUserSession; + const CognitoUserSession = () => {}; + + CognitoUserSession.prototype.CognitoUserSession = options => { + CognitoUserSession.prototype.options = options; + return CognitoUserSession; + }; + + CognitoUserSession.prototype.getIdToken = () => { + return { + getJwtToken: () => { + return null; + }, + }; + }; + + CognitoUserSession.prototype.getAccessToken = () => { + return 'accessToken'; + }; + + CognitoUserSession.prototype.isValid = () => { + return true; + }; + + CognitoUserSession.prototype.getRefreshToken = () => { + return 'refreshToken'; + }; + + return CognitoUserSession; }); jest.mock('amazon-cognito-identity-js/lib/CognitoUserPool', () => { - const CognitoUserPool = () => {}; - - CognitoUserPool.prototype.CognitoUserPool = (options) => { - CognitoUserPool.prototype.options = options; - return CognitoUserPool; - }; - - CognitoUserPool.prototype.getCurrentUser = () => { - return "currentUser"; - }; - - CognitoUserPool.prototype.signUp = (username, password, signUpAttributeList, validationData, callback) => { - callback(null, 'signUpResult'); - }; - - return CognitoUserPool; + const CognitoUserPool = () => {}; + + CognitoUserPool.prototype.CognitoUserPool = options => { + CognitoUserPool.prototype.options = options; + return CognitoUserPool; + }; + + CognitoUserPool.prototype.getCurrentUser = () => { + return 'currentUser'; + }; + + CognitoUserPool.prototype.signUp = ( + username, + password, + signUpAttributeList, + validationData, + callback + ) => { + callback(null, 'signUpResult'); + }; + + return CognitoUserPool; }); jest.mock('amazon-cognito-identity-js/lib/CognitoUser', () => { - const CognitoUser = () => { }; - - CognitoUser.prototype.CognitoUser = (options) => { - CognitoUser.prototype.options = options; - return CognitoUser; - }; - - CognitoUser.prototype.getSession = (callback) => { - // throw 3; - callback(null, "session"); - }; - - CognitoUser.prototype.getUserAttributes = (callback) => { - callback(null, "attributes"); - }; - - CognitoUser.prototype.getAttributeVerificationCode = (attr, callback) => { - callback.onSuccess("success"); - }; - - CognitoUser.prototype.verifyAttribute = (attr, code, callback) => { - callback.onSuccess("success"); - }; - - CognitoUser.prototype.authenticateUser = (authenticationDetails, callback) => { - callback.onSuccess('session'); - }; - - CognitoUser.prototype.sendMFACode = (code, callback) => { - callback.onSuccess('session'); - }; - - CognitoUser.prototype.resendConfirmationCode = (callback) => { - callback(null, 'result'); - }; - - CognitoUser.prototype.changePassword = (oldPassword, newPassword, callback) => { - callback(null, 'SUCCESS'); - }; - - CognitoUser.prototype.forgotPassword = (callback) => { - callback.onSuccess(); - }; - - CognitoUser.prototype.confirmPassword = (code, password, callback) => { - callback.onSuccess(); - }; - - CognitoUser.prototype.signOut = () => { - - }; - - CognitoUser.prototype.globalSignOut = (callback) => { - callback.onSuccess(); - }; - - CognitoUser.prototype.confirmRegistration = (confirmationCode, forceAliasCreation, callback) => { - callback(null, 'Success'); - }; - - CognitoUser.prototype.completeNewPasswordChallenge = (password, requiredAttributes, callback) => { - callback.onSuccess('session'); - }; - - CognitoUser.prototype.updateAttributes = (attributeList, callback) => { - callback(null, 'SUCCESS'); - }; - - CognitoUser.prototype.setAuthenticationFlowType = (type) => { - - }; - - CognitoUser.prototype.initiateAuth = (authenticationDetails, callback) => { - callback.customChallenge('challengeParam'); - }; - - CognitoUser.prototype.sendCustomChallengeAnswer = (challengeAnswer, callback) => { - callback.onSuccess('session'); - }; - - CognitoUser.prototype.refreshSession = (refreshToken, callback) => { - callback(null, 'session'); - } - - CognitoUser.prototype.getUsername = () => { - return 'username'; - } - - CognitoUser.prototype.getUserData = (callback) => { - callback(null, 'data'); - } - - return CognitoUser; + const CognitoUser = () => {}; + + CognitoUser.prototype.CognitoUser = options => { + CognitoUser.prototype.options = options; + return CognitoUser; + }; + + CognitoUser.prototype.getSession = callback => { + // throw 3; + callback(null, 'session'); + }; + + CognitoUser.prototype.getUserAttributes = callback => { + callback(null, 'attributes'); + }; + + CognitoUser.prototype.getAttributeVerificationCode = (attr, callback) => { + callback.onSuccess('success'); + }; + + CognitoUser.prototype.verifyAttribute = (attr, code, callback) => { + callback.onSuccess('success'); + }; + + CognitoUser.prototype.authenticateUser = ( + authenticationDetails, + callback + ) => { + callback.onSuccess('session'); + }; + + CognitoUser.prototype.sendMFACode = (code, callback) => { + callback.onSuccess('session'); + }; + + CognitoUser.prototype.resendConfirmationCode = callback => { + callback(null, 'result'); + }; + + CognitoUser.prototype.changePassword = ( + oldPassword, + newPassword, + callback + ) => { + callback(null, 'SUCCESS'); + }; + + CognitoUser.prototype.forgotPassword = callback => { + callback.onSuccess(); + }; + + CognitoUser.prototype.confirmPassword = (code, password, callback) => { + callback.onSuccess(); + }; + + CognitoUser.prototype.signOut = () => {}; + + CognitoUser.prototype.globalSignOut = callback => { + callback.onSuccess(); + }; + + CognitoUser.prototype.confirmRegistration = ( + confirmationCode, + forceAliasCreation, + callback + ) => { + callback(null, 'Success'); + }; + + CognitoUser.prototype.completeNewPasswordChallenge = ( + password, + requiredAttributes, + callback + ) => { + callback.onSuccess('session'); + }; + + CognitoUser.prototype.updateAttributes = (attributeList, callback) => { + callback(null, 'SUCCESS'); + }; + + CognitoUser.prototype.setAuthenticationFlowType = type => {}; + + CognitoUser.prototype.initiateAuth = (authenticationDetails, callback) => { + callback.customChallenge('challengeParam'); + }; + + CognitoUser.prototype.sendCustomChallengeAnswer = ( + challengeAnswer, + callback + ) => { + callback.onSuccess('session'); + }; + + CognitoUser.prototype.refreshSession = (refreshToken, callback) => { + callback(null, 'session'); + }; + + CognitoUser.prototype.getUsername = () => { + return 'username'; + }; + + CognitoUser.prototype.getUserData = callback => { + callback(null, 'data'); + }; + + return CognitoUser; }); import { AuthOptions, SignUpParams, AwsCognitoOAuthOpts } from '../src/types'; import Auth from '../src/Auth'; import Cache from '@aws-amplify/cache'; -import { CookieStorage, CognitoUserPool, CognitoUser, CognitoUserSession, CognitoIdToken, CognitoAccessToken } from 'amazon-cognito-identity-js'; +import { + CookieStorage, + CognitoUserPool, + CognitoUser, + CognitoUserSession, + CognitoIdToken, + CognitoAccessToken, +} from 'amazon-cognito-identity-js'; import { CognitoIdentityCredentials } from 'aws-sdk'; import { Credentials, GoogleOAuth, StorageHelper } from '@aws-amplify/core'; import { AuthError, NoUserPoolError } from '../src/Errors'; import { AuthErrorTypes } from '../src/types/Auth'; -const authOptions : AuthOptions = { - userPoolId: "awsUserPoolsId", - userPoolWebClientId: "awsUserPoolsWebClientId", - region: "region", - identityPoolId: "awsCognitoIdentityPoolId", - mandatorySignIn: false +const authOptions: AuthOptions = { + userPoolId: 'awsUserPoolsId', + userPoolWebClientId: 'awsUserPoolsWebClientId', + region: 'region', + identityPoolId: 'awsCognitoIdentityPoolId', + mandatorySignIn: false, }; -const authOptionsWithNoUserPoolId : AuthOptions = { - userPoolWebClientId: "awsUserPoolsWebClientId", - region: "region", - identityPoolId: "awsCognitoIdentityPoolId", - mandatorySignIn: false +const authOptionsWithNoUserPoolId: AuthOptions = { + userPoolWebClientId: 'awsUserPoolsWebClientId', + region: 'region', + identityPoolId: 'awsCognitoIdentityPoolId', + mandatorySignIn: false, }; const userPool = new CognitoUserPool({ - UserPoolId: authOptions.userPoolId, - ClientId: authOptions.userPoolWebClientId + UserPoolId: authOptions.userPoolId, + ClientId: authOptions.userPoolWebClientId, }); const idToken = new CognitoIdToken({ IdToken: 'idToken' }); const accessToken = new CognitoAccessToken({ AccessToken: 'accessToken' }); const session = new CognitoUserSession({ - IdToken: idToken, - AccessToken: accessToken + IdToken: idToken, + AccessToken: accessToken, }); const USER_ADMIN_SCOPE = 'aws.cognito.signin.user.admin'; describe('auth unit test', () => { - describe('signUp', () => { - test('happy case with object attr', async () => { - const spyon = jest.spyOn(CognitoUserPool.prototype, "signUp"); - const auth = new Auth(authOptions); - - const attrs = { - username: 'username', - password: 'password', - attributes: { - email: 'email', - phone_number: 'phone_number', - otherAttrs: 'otherAttrs' - } - }; - - expect(await auth.signUp(attrs)).toBe('signUpResult'); - - spyon.mockClear(); - }); - - test('object attr with null username', async () => { - const auth = new Auth(authOptions); - - const attrs = { - username: null, - password: 'password', - attributes: { - email: 'email', - phone_number: 'phone_number', - otherAttrs: 'otherAttrs' - } - }; - expect.assertions(1); - expect(auth.signUp(attrs).then()).rejects.toThrow(AuthError); - }); - - test('callback error', async () => { - const spyon = jest.spyOn(CognitoUserPool.prototype, "signUp") - .mockImplementationOnce((username, password, signUpAttributeList, validationData, callback) => { - callback('err', null); - }); - - const auth = new Auth(authOptions); - - expect.assertions(1); - try { - const attrs = { - username: 'username', - password: 'password', - attributes: { - email: 'email', - phone_number: 'phone_number', - otherAttrs: 'otherAttrs' - } - }; - await auth.signUp(attrs); - } catch (e) { - expect(e).toBe('err'); - } - - spyon.mockClear(); - }); - - test('no config', async () => { - const auth = new Auth(undefined); - const errorMessage = new NoUserPoolError(AuthErrorTypes.NoConfig); - - expect.assertions(2); - expect(auth.signUp('username', 'password', 'email', 'phone').then()).rejects.toThrow(NoUserPoolError); - expect(auth.signUp('username', 'password', 'email', 'phone').then()).rejects.toEqual(errorMessage); - }); - - test('no user pool in config', async () => { - const auth = new Auth(authOptionsWithNoUserPoolId); - const errorMessage = new NoUserPoolError(AuthErrorTypes.MissingAuthConfig); - - expect.assertions(2); - expect(auth.signUp('username', 'password', 'email', 'phone').then()).rejects.toThrow(NoUserPoolError); - expect(auth.signUp('username', 'password', 'email', 'phone').then()).rejects.toEqual(errorMessage); - }); - - test('no username', async () => { - const auth = new Auth(authOptions); - expect.assertions(1); - expect(auth.signUp(null, 'password', 'email', 'phone').then()).rejects.toThrow(AuthError); - }); - - test('no password', async () => { - const auth = new Auth(authOptions); - const errorMessage = new AuthError(AuthErrorTypes.EmptyPassword); - - expect.assertions(2); - expect(auth.signUp('username', null, 'email', 'phone').then()).rejects.toThrow(AuthError); - expect(auth.signUp('username', null, 'email', 'phone').then()).rejects.toEqual(errorMessage); - }); - - test('only username', async () => { - const auth = new Auth(authOptions); - const errorMessage = new AuthError(AuthErrorTypes.EmptyPassword); - - expect.assertions(2); - expect(auth.signUp('username').then()).rejects.toThrow(AuthError); - expect(auth.signUp('username').then()).rejects.toEqual(errorMessage); - }); - }); - - describe('confirmSignUp', () => { - test('happy case', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "confirmRegistration"); - const auth = new Auth(authOptions); - - expect.assertions(1); - expect(await auth.confirmSignUp('username', 'code')).toBe('Success'); - - spyon.mockClear(); - }); - - test('with options', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "confirmRegistration"); - const auth = new Auth(authOptions); - - expect.assertions(1); - expect(await auth.confirmSignUp('username', 'code', {forceAliasCreation: false})).toBe('Success'); - - spyon.mockClear(); - }); - - test('callback err', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "confirmRegistration") - .mockImplementationOnce((confirmationCode, forceAliasCreation, callback) => { - callback('err', null); - }); - - const auth = new Auth(authOptions); - - expect.assertions(1); - try { - await auth.confirmSignUp('username', 'code'); - } catch (e) { - expect(e).toBe('err'); - } - - spyon.mockClear(); - }); - - test('no user pool in config', async () => { - const auth = new Auth(authOptionsWithNoUserPoolId); - const errorMessage = new NoUserPoolError(AuthErrorTypes.MissingAuthConfig); - - expect.assertions(2); - expect(auth.confirmSignUp('username', 'code').then()).rejects.toThrow(NoUserPoolError); - expect(auth.confirmSignUp('username', 'code').then()).rejects.toEqual(errorMessage); - }); - - test('no user name', async () => { - const auth = new Auth(authOptions); - const errorMessage = new AuthError(AuthErrorTypes.EmptyUsername); - - expect.assertions(2); - expect(auth.confirmSignUp(null, 'code').then()).rejects.toThrow(AuthError); - expect(auth.confirmSignUp(null, 'code').then()).rejects.toEqual(errorMessage); - }); - - test('no code', async () => { - const auth = new Auth(authOptions); - const errorMessage = new AuthError(AuthErrorTypes.EmptyCode); - - expect.assertions(2); - expect(auth.confirmSignUp('username', null).then()).rejects.toThrow(AuthError); - expect(auth.confirmSignUp('username', null).then()).rejects.toEqual(errorMessage); - }); - }); - - describe('resendSignUp', () => { - test('happy case', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "resendConfirmationCode"); - const auth = new Auth(authOptions); - - expect.assertions(1); - expect(await auth.resendSignUp('username')).toBe('result'); - - spyon.mockClear(); - }); - - test('callback err', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "resendConfirmationCode") - .mockImplementationOnce((callback) => { - callback('err', null); - }); - - const auth = new Auth(authOptions); - - expect.assertions(1); - try { - await auth.resendSignUp('username'); - } catch (e) { - expect(e).toBe('err'); - } - - spyon.mockClear(); - }); - - test('no user pool in config', async () => { - const auth = new Auth(authOptionsWithNoUserPoolId); - const errorMessage = new NoUserPoolError(AuthErrorTypes.MissingAuthConfig); - - expect.assertions(2); - expect(auth.resendSignUp('username').then()).rejects.toThrow(NoUserPoolError); - expect(auth.resendSignUp('username').then()).rejects.toEqual(errorMessage); - }); - - test('no username', async () => { - const auth = new Auth(authOptions); - const errorMessage = new AuthError(AuthErrorTypes.EmptyUsername); - - expect.assertions(2); - expect(auth.resendSignUp(null).then()).rejects.toThrow(AuthError); - expect(auth.resendSignUp(null).then()).rejects.toEqual(errorMessage); - }); - }); - - describe('signIn', () => { - test('happy case with password', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'authenticateUser') - .mockImplementationOnce((authenticationDetails, callback) => { - callback.onSuccess(session); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon2 = jest.spyOn(auth, 'currentUserPoolUser').mockImplementationOnce(() => { - return Promise.resolve(user); - }); - - expect.assertions(2); - expect(await auth.signIn('username', 'password')).toEqual(user); - expect(spyon2).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('throw error if failed to call currentUserPoolUser after signing in', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'authenticateUser') - .mockImplementationOnce((authenticationDetails, callback) => { - callback.onSuccess(session); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon2 = jest.spyOn(auth, 'currentUserPoolUser').mockImplementationOnce(() => { - return Promise.reject('User is disabled'); - }); - expect.assertions(2); - try { - await auth.signIn('username', 'password'); - } catch (e) { - expect(e).toBe('User is disabled'); - expect(spyon2).toBeCalled(); - } - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('happy case using cookie storage', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'authenticateUser') - .mockImplementationOnce((_authenticationDetails, callback) => { - callback.onSuccess(session); - }); - - const auth = new Auth({ ...authOptions, cookieStorage: { domain: ".example.com" } }); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool, - Storage: new CookieStorage({ domain: ".yourdomain.com" }) - }); - - const spyon2 = jest.spyOn(auth, 'currentUserPoolUser').mockImplementationOnce(() => { - return Promise.resolve(user); - }); - - expect.assertions(1); - expect(await auth.signIn('username', 'password')).toEqual(user); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('onFailure', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "authenticateUser") - .mockImplementationOnce((authenticationDetails, callback) => { - callback.onFailure('err'); - }); - - const auth = new Auth(authOptions); - - expect.assertions(1); - try { - await auth.signIn('username', 'password'); - } catch (e) { - expect(e).toBe('err'); - } - - spyon.mockClear(); - }); - - test('mfaRequired', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "authenticateUser") - .mockImplementationOnce((authenticationDetails, callback) => { - callback.mfaRequired('challengeName', 'challengeParam'); - }); - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - const userAfterSignedIn = Object.assign( - {}, - user, - { - "challengeName": "challengeName", - "challengeParam": "challengeParam" - }); - - expect.assertions(1); - expect(await auth.signIn('username', 'password')).toEqual(userAfterSignedIn); - - spyon.mockClear(); - }); - - test('mfaSetup', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "authenticateUser") - .mockImplementationOnce((authenticationDetails, callback) => { - callback.mfaSetup('challengeName', 'challengeParam'); - }); - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - const userAfterSignedIn = Object.assign( - {}, - user, - { - "challengeName": "challengeName", - "challengeParam": "challengeParam" - }); - - expect.assertions(1); - expect(await auth.signIn('username', 'password')).toEqual(userAfterSignedIn); - - spyon.mockClear(); - }); - - test('totpRequired', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "authenticateUser") - .mockImplementationOnce((authenticationDetails, callback) => { - callback.totpRequired('challengeName', 'challengeParam'); - }); - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - const userAfterSignedIn = Object.assign( - {}, - user, - { - "challengeName": "challengeName", - "challengeParam": "challengeParam" - }); - - expect.assertions(1); - expect(await auth.signIn('username', 'password')).toEqual(userAfterSignedIn); - - spyon.mockClear(); - }); - - test('selectMFAType', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "authenticateUser") - .mockImplementationOnce((authenticationDetails, callback) => { - callback.selectMFAType('challengeName', 'challengeParam'); - }); - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - const userAfterSignedIn = Object.assign( - {}, - user, - { - "challengeName": "challengeName", - "challengeParam": "challengeParam" - }); - - expect.assertions(1); - expect(await auth.signIn('username', 'password')).toEqual(userAfterSignedIn); - - spyon.mockClear(); - }); - - test('newPasswordRequired', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "authenticateUser") - .mockImplementationOnce((authenticationDetails, callback) => { - callback.newPasswordRequired('userAttributes', 'requiredAttributes'); - }); - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - const userAfterSignedIn = Object.assign( - {}, - user, - { - "challengeName": "NEW_PASSWORD_REQUIRED", - "challengeParam": { - "requiredAttributes": "requiredAttributes", - "userAttributes": "userAttributes" - } - }); - - expect.assertions(1); - expect(await auth.signIn('username', 'password')).toEqual(userAfterSignedIn); - - spyon.mockClear(); - }); - - test('customChallenge', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'authenticateUser') - .mockImplementationOnce((authenticationDetails, callback) => { - callback.customChallenge('challengeParam'); - }); - const spyon2 = jest.spyOn(CognitoUser.prototype, 'setAuthenticationFlowType') - .mockImplementationOnce((type) => { - - }); - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - const userAfterSignedIn = Object.assign( - {}, - user, - { - "challengeName": "CUSTOM_CHALLENGE", - "challengeParam": "challengeParam" - }); - - expect.assertions(2); - expect(await auth.signIn('username')).toEqual(userAfterSignedIn); - expect(spyon2).toBeCalledWith('CUSTOM_AUTH'); - - spyon2.mockClear(); - spyon.mockClear(); - }); - - test('no userPool', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'authenticateUser'); - - // @ts-ignore - const auth = new Auth(authOptionsWithNoUserPoolId); - - expect.assertions(1); - try { - await auth.signIn('username', 'password'); - } catch (e) { - expect(e).not.toBeNull(); - } - - spyon.mockClear(); - }); - - test('no username', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'authenticateUser'); - const auth = new Auth(authOptions); - - expect.assertions(1); - try { - await auth.signIn(null, 'password'); - } catch (e) { - expect(e).not.toBeNull(); - } - - spyon.mockClear(); - }); - }); - - describe("confirmSignIn", () => { - test('happy case', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "sendMFACode") - .mockImplementationOnce((code, callback) => { - callback.onSuccess(session); - }); - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - expect(await auth.confirmSignIn(user, 'code', null)).toEqual(user); - - spyon.mockClear(); - }); - - test('onFailure', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "sendMFACode") - .mockImplementationOnce((code, callback) => { - callback.onFailure('err'); - }); - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - try { - await auth.confirmSignIn(user, 'code', null); - } catch (e) { - expect(e).toBe('err'); - } - - spyon.mockClear(); - }); - - test('no code', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "sendMFACode"); - const auth = new Auth(authOptions); - - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - try { - await auth.confirmSignIn(user, null, null); - } catch (e) { - expect(e).not.toBeNull(); - } - - spyon.mockClear(); - }); - }); - - describe('completeNewPassword', () => { - test('happy case', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'completeNewPasswordChallenge') - .mockImplementationOnce((password, requiredAttributes, callback) => { - callback.onSuccess(session); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - expect(await auth.completeNewPassword(user, 'password', {})).toEqual(user); - - spyon.mockClear(); - }); - - test('on Failure', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'completeNewPasswordChallenge') - .mockImplementationOnce((password, requiredAttributes, callback) => { - callback.onFailure('err'); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - try { - await auth.completeNewPassword(user, 'password', {}); - } catch (e) { - expect(e).toBe('err'); - } - - spyon.mockClear(); - }); - - test('mfaRequired', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'completeNewPasswordChallenge') - .mockImplementationOnce((password, requiredAttributes, callback) => { - callback.mfaRequired('challengeName', 'challengeParam'); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - expect(await auth.completeNewPassword(user, 'password', {})).toBe(user); - - spyon.mockClear(); - }); - - test('mfaSetup', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'completeNewPasswordChallenge') - .mockImplementationOnce((password, requiredAttributes, callback) => { - callback.mfaSetup('challengeName', 'challengeParam'); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - expect(await auth.completeNewPassword(user, 'password', {})).toBe(user); - - spyon.mockClear(); - }); - - test('no password', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const errorMessage = new AuthError(AuthErrorTypes.EmptyPassword); - - expect.assertions(2); - await expect(auth.completeNewPassword(user, null, {}).then()).rejects.toThrow(AuthError); - await expect(auth.completeNewPassword(user, null, {}).then()).rejects.toEqual(errorMessage); - }); - }); - - describe('userAttributes', () => { - test('happy case', async () => { - const spyon = jest.spyOn(Auth.prototype, 'userSession') - .mockImplementationOnce((user) => { - return new Promise((res, rej) => { - res('session'); - }); - }); - - const spyon2 = jest.spyOn(CognitoUser.prototype, 'getUserAttributes'); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - expect(await auth.userAttributes(user)).toBe('attributes'); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('get userattributes failed', async () => { - const spyon = jest.spyOn(Auth.prototype, 'userSession') - .mockImplementationOnce((user) => { - return new Promise((res, rej) => { - res('session'); - }); - }); - - const spyon2 = jest.spyOn(CognitoUser.prototype, 'getUserAttributes') - .mockImplementationOnce((callback) => { - callback('err'); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - try { - await auth.userAttributes(user); - } catch (e) { - expect(e).toBe('err'); - } - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); - - describe('currentSession', () => { - test('happy case', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(auth, "currentUserPoolUser") - .mockImplementationOnce(() => { - return Promise.resolve(user); - }); - - const spyon2 = jest.spyOn(Auth.prototype, 'userSession').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(session); - }) - }); - expect.assertions(1); - expect(await auth.currentSession()).toEqual(session); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('no current session', async () => { - const auth = new Auth(authOptions); - - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(auth, "currentUserPoolUser") - .mockImplementationOnce(() => { - return Promise.resolve(user); - }); - - const spyon2 = jest.spyOn(auth, 'userSession').mockImplementationOnce(() => { - return Promise.reject('cannot get the session'); - }); - - expect.assertions(1); - try { - await auth.currentSession(); - } catch (e) { - expect(e).toBe('cannot get the session'); - } - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('no current user', async () => { - const auth = new Auth(authOptions); - - const spyon = jest.spyOn(auth, "currentUserPoolUser") - .mockImplementationOnce(() => { - return Promise.reject('no current user') - }); - - expect.assertions(1); - try { - await auth.currentSession(); - } catch (e) { - expect(e).toBe('no current user'); - } - - spyon.mockClear(); - }); - - test('no UserPool', async () => { - const auth = new Auth({ - userPoolId: undefined, - userPoolWebClientId: "awsUserPoolsWebClientId", - region: "region", - identityPoolId: "awsCognitoIdentityPoolId", - mandatorySignIn: false - }); - const errorMessage = new NoUserPoolError(AuthErrorTypes.MissingAuthConfig); - - expect.assertions(2); - expect(auth.currentSession().then()).rejects.toThrow(NoUserPoolError); - expect(auth.currentSession().then()).rejects.toEqual(errorMessage); - }); - }); - - describe('currentAuthenticatedUser', () => { - test('happy case with source userpool', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(Auth.prototype, 'currentUserPoolUser') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(user); - }); - }); - expect.assertions(1); - expect(await auth.currentAuthenticatedUser()).toEqual(user); - - spyon.mockClear(); - }); - - test('happy case with source federation', async () => { - const spyon = jest.spyOn(StorageHelper.prototype, 'getStorage').mockImplementation(() => { - return { - getItem() { - return JSON.stringify({ - user: 'federated_user' - }); - } - } - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - expect(await auth.currentAuthenticatedUser()).toBe('federated_user'); - - spyon.mockClear(); - }); - }); - - describe('userSession test', () => { - test('happy case', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'getSession').mockImplementationOnce((callback) => { - callback(null, session); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - expect(await auth.userSession(user)).toEqual(session); - - spyon.mockClear(); - }); - - test('callback error', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(CognitoUser.prototype, "getSession") - .mockImplementationOnce((callback) => { - callback('err', null); - }); - - expect.assertions(1); - try { - await auth.userSession(user); - } catch (e) { - expect(e).toBe('err'); - } - - spyon.mockClear(); - }); - - test('no user', async () => { - const auth = new Auth(authOptions); - const user = null; - - expect.assertions(1); - try { - await auth.userSession(user); - } catch (e) { - expect(e).not.toBeNull(); - } - }); - }); - - describe('currentUserCredentials test', () => { - test('with federated info', async () => { - const spyon = jest.spyOn(StorageHelper.prototype, 'getStorage').mockImplementation(() => { - return { - getItem() { - return JSON.stringify({ - provider: 'google', - token: 'token' - }); - } - } - }); - - const auth = new Auth(authOptions); - - const spyon2 = jest.spyOn(Credentials, 'refreshFederatedToken').mockImplementationOnce(() => { - return Promise.resolve('cred'); - }); - - expect.assertions(1); - expect(await auth.currentUserCredentials()).toBe('cred'); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('with cognito session', async () => { - const spyon = jest.spyOn(StorageHelper.prototype, 'getStorage').mockImplementation(() => { - return { - getItem() { - return null; - } - } - }); - const auth = new Auth(authOptions); - - const spyon2 = jest.spyOn(auth, 'currentSession').mockImplementationOnce(() => { - return Promise.resolve('session'); - }); - - const spyon3 = jest.spyOn(Credentials, 'set').mockImplementationOnce(() => { - return Promise.resolve('cred'); - }); - - expect.assertions(1); - expect(await auth.currentUserCredentials()).toBe('cred'); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - }); - - test('with guest', async () => { - const spyon = jest.spyOn(StorageHelper.prototype, 'getStorage').mockImplementation(() => { - return { - getItem() { - return null; - } - } - }); - const auth = new Auth(authOptions); - - const spyon2 = jest.spyOn(auth, 'currentSession').mockImplementationOnce(() => { - return Promise.reject('err'); - }); - - const spyon3 = jest.spyOn(Credentials, 'set').mockImplementationOnce(() => { - return Promise.resolve('cred'); - }); - - expect.assertions(1); - expect(await auth.currentUserCredentials()).toBe('cred'); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - }); - - test('json parse error', async () => { - const spyon = jest.spyOn(StorageHelper.prototype, 'getStorage').mockImplementation(() => { - return { - getItem() { - return undefined; - } - } - }); - const auth = new Auth(authOptions); - - const spyon2 = jest.spyOn(auth, 'currentSession').mockImplementationOnce(() => { - return Promise.resolve('session'); - }); - - const spyon3 = jest.spyOn(Credentials, 'set').mockImplementationOnce(() => { - return Promise.resolve('cred'); - }); - - expect.assertions(1); - expect(await auth.currentUserCredentials()).toBe('cred'); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - }); - }); - - describe('currentCrendentials', () => { - const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { - return; - }); - - const auth = new Auth(authOptions); - - auth.currentCredentials(); - expect(spyon).toBeCalled(); - spyon.mockClear(); - }); - - describe('verifyUserAttribute test', () => { - test('happy case', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "getAttributeVerificationCode"); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - await auth.verifyUserAttribute(user, {email: 'xxx@xxx.com'}); - expect(spyon).toBeCalled(); - - spyon.mockClear(); - - }); - - test('onFailure', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "getAttributeVerificationCode") - .mockImplementationOnce((attr, callback) => { - callback.onFailure('err'); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - try { - await auth.verifyUserAttribute(user, {}); - } catch (e) { - expect(e).toBe("err"); - } - - spyon.mockClear(); - }); - }); - - describe('verifyUserAttributeSubmit', () => { - test('happy case', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "verifyAttribute"); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - expect(await auth.verifyUserAttributeSubmit(user, {}, 'code')).toBe("success"); - - spyon.mockClear(); - }); - - test('onFailure', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "verifyAttribute") - .mockImplementationOnce((attr, code, callback) => { - callback.onFailure('err'); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect.assertions(1); - try { - await auth.verifyUserAttributeSubmit(user, {}, 'code'); - } catch (e) { - expect(e).toBe("err"); - } - - spyon.mockClear(); - }); - - test('code empty', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - const errorMessage = new AuthError(AuthErrorTypes.EmptyCode); - - expect.assertions(2); - expect(auth.verifyUserAttributeSubmit(user, {}, null).then()).rejects.toThrow(AuthError); - expect(auth.verifyUserAttributeSubmit(user, {}, null).then()).rejects.toEqual(errorMessage); - }); - }); - - describe('verifyCurrentUserAttribute test', () => { - test('happy case', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(Auth.prototype, 'currentUserPoolUser') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(user); - }); - }); - - const spyon2 = jest.spyOn(Auth.prototype, 'verifyUserAttribute') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(); - }); - }); - - await auth.verifyCurrentUserAttribute('attr'); - - expect.assertions(2); - expect(spyon).toBeCalled(); - expect(spyon2).toBeCalledWith(user, 'attr'); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); - - describe('verifyCurrentUserAttributeSubmit test', () => { - test('happy case', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(Auth.prototype, 'currentUserPoolUser') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(user); - }); - }); - - const spyon2 = jest.spyOn(Auth.prototype, 'verifyUserAttributeSubmit') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(); - }); - }); - - await auth.verifyCurrentUserAttributeSubmit('attr', 'code'); - - expect.assertions(2); - expect(spyon).toBeCalled(); - expect(spyon2).toBeCalledWith(user, 'attr', 'code'); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); - - describe('signOut test', () => { - test('happy case', async () => { - const auth = new Auth(authOptions); - - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(Credentials, 'clear').mockImplementationOnce(() => { - return - }); - const spyon2 = jest.spyOn(CognitoUserPool.prototype, "getCurrentUser") - .mockImplementationOnce(() => { - return user; - }); - - await auth.signOut(); - - expect.assertions(2); - expect(spyon).toBeCalled(); - expect(spyon2).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('happy case for source userpool', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - auth['credentials_source'] = 'aws'; - auth['credentials'] = new CognitoIdentityCredentials({ - IdentityPoolId: 'identityPoolId' - }); - - const spyonAuth = jest.spyOn(Auth.prototype, "currentUserCredentials") - .mockImplementationOnce(() => { - return new Promise((resolve, reject) => { resolve(); }); - }); - const spyon = jest.spyOn(CognitoUserPool.prototype, "getCurrentUser") - .mockImplementationOnce(() => { - return user; - }); - const spyon2 = jest.spyOn(CognitoUser.prototype, "signOut"); - // @ts-ignore - - await auth.signOut(); - - expect.assertions(1); - expect(spyon2).toBeCalled(); - - spyonAuth.mockClear(); - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('happy case for globalSignOut', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyonAuth = jest.spyOn(Credentials, "clear") - .mockImplementationOnce(() => { - return Promise.resolve(); - }); - const spyon = jest.spyOn(CognitoUserPool.prototype, "getCurrentUser") - .mockImplementationOnce(() => { - return user; - }); - const spyon2 = jest.spyOn(CognitoUser.prototype, "globalSignOut"); - - await auth.signOut({global: true}); - - expect.assertions(1); - expect(spyon2).toBeCalled(); - - spyonAuth.mockClear(); - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('happy case for no userpool', async () => { - // @ts-ignore - const auth = new Auth(authOptionsWithNoUserPoolId); - - expect(await auth.signOut()).toBeUndefined(); - }); - - test('no User in userpool', async () => { - const auth = new Auth(authOptions); - - const spyon = jest.spyOn(CognitoUserPool.prototype, 'getCurrentUser') - .mockImplementationOnce(() => { - return null; - }); - expect(await auth.signOut()).toBeUndefined(); - - spyon.mockClear(); - }); - - test('get guest credentials failed', async() => { - const auth = new Auth(authOptionsWithNoUserPoolId); - - const cognitoCredentialSpyon = jest.spyOn(CognitoIdentityCredentials.prototype, 'get').mockImplementation((callback) => { - callback(null); - }); - - expect(await auth.signOut()).toBeUndefined(); - - cognitoCredentialSpyon.mockClear(); - }); - }); - - describe('changePassword', () => { - test('happy case', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - const oldPassword = 'oldPassword1'; - const newPassword = 'newPassword1.'; - - const spyon = jest.spyOn(Auth.prototype, 'userSession').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(session); - }) - }); - - expect.assertions(1); - expect(await auth.changePassword(user, oldPassword, newPassword)).toBe('SUCCESS'); - - spyon.mockClear(); - }); - }); - - describe('forgotPassword', () => { - test('happy case', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "forgotPassword"); - - const auth = new Auth(authOptions); - - expect.assertions(1); - expect(await auth.forgotPassword('username')).toBeUndefined(); - - spyon.mockClear(); - }); - - test('onFailue', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "forgotPassword") - .mockImplementationOnce((callback) => { - callback.onFailure('err'); - }); - - const auth = new Auth(authOptions); - - expect.assertions(1); - try { - await auth.forgotPassword('username'); - } catch (e) { - expect(e).toBe('err'); - } - - spyon.mockClear(); - }); - - test('inputVerficationCode', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "forgotPassword") - .mockImplementationOnce((callback) => { - callback.inputVerificationCode('data'); - }); - - const auth = new Auth(authOptions); - - expect.assertions(1); - expect(await auth.forgotPassword('username')).toBe('data'); - - spyon.mockClear(); - }); - - test('no user pool id', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "forgotPassword"); - - const auth = new Auth(authOptionsWithNoUserPoolId); - const errorMessage = new NoUserPoolError(AuthErrorTypes.MissingAuthConfig); - - expect.assertions(2); - expect(auth.forgotPassword('username').then()).rejects.toThrow(NoUserPoolError); - expect(auth.forgotPassword('username').then()).rejects.toEqual(errorMessage); - - spyon.mockClear(); - }); - - test('no username', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "forgotPassword"); - - const auth = new Auth(authOptions); - - expect.assertions(1); - try { - await auth.forgotPassword(null); - } catch (e) { - expect(e).not.toBeNull(); - } - spyon.mockClear(); - }); - }); - - describe('forgotPasswordSubmit', () => { - test('happy case', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "confirmPassword"); - - const auth = new Auth(authOptions); - - expect.assertions(1); - expect(await auth.forgotPasswordSubmit('username', 'code', 'password')).toBeUndefined(); - - spyon.mockClear(); - }); - - test('confirmPassword failed', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, "confirmPassword") - .mockImplementationOnce((code, password, callback) => { - callback.onFailure('err'); - }); - - const auth = new Auth(authOptions); - - expect.assertions(1); - try { - await auth.forgotPasswordSubmit('username', 'code', 'password'); - } catch (e) { - expect(e).toBe('err'); - } - - spyon.mockClear(); - }); - - test('no user pool in config', async () => { - const auth = new Auth(authOptionsWithNoUserPoolId); - const errorMessage = new NoUserPoolError(AuthErrorTypes.MissingAuthConfig); - - expect.assertions(2); - expect(auth.forgotPasswordSubmit('username', 'code', 'password').then()).rejects.toThrow(NoUserPoolError); - expect(auth.forgotPasswordSubmit('username', 'code', 'password').then()).rejects.toEqual(errorMessage); - }); - - test('no username', async () => { - const auth = new Auth(authOptions); - const errorMessage = new AuthError(AuthErrorTypes.EmptyUsername); - - expect.assertions(2); - expect(auth.forgotPasswordSubmit(null, 'code', 'password').then()).rejects.toThrow(AuthError); - expect(auth.forgotPasswordSubmit(null, 'code', 'password').then()).rejects.toEqual(errorMessage); - }); - - test('no code', async () => { - const auth = new Auth(authOptions); - const errorMessage = new AuthError(AuthErrorTypes.EmptyCode); - - expect.assertions(2); - expect(auth.forgotPasswordSubmit('username', null, 'password').then()).rejects.toThrow(AuthError); - expect(auth.forgotPasswordSubmit('username', null, 'password').then()).rejects.toEqual(errorMessage); - }); - - test('no password', async () => { - const auth = new Auth(authOptions); - const errorMessage = new AuthError(AuthErrorTypes.EmptyPassword); - - expect.assertions(2); - expect(auth.forgotPasswordSubmit('username', 'code', null).then()).rejects.toThrow(AuthError); - expect(auth.forgotPasswordSubmit('username', 'code', null).then()).rejects.toEqual(errorMessage); - }); - }); - - describe('currentUserInfo test', () => { - test('happy case with aws or userpool source', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(Auth.prototype, 'currentUserPoolUser') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(user); - }); - }); - - const spyon2 = jest.spyOn(Auth.prototype, 'userAttributes') - .mockImplementationOnce(() => { - auth['credentials'] = new CognitoIdentityCredentials({ - IdentityPoolId: 'identityPoolId', - IdentityId: 'identityId' - }); - auth['credentials']['identityId'] = 'identityId'; - return new Promise((res, rej) => { - res([ - { Name: 'email', Value: 'email' }, - { Name: 'phone_number', Value: 'phone_number' }, - { Name: 'email_verified', Value: 'false' }, - { Name: 'phone_number_verified', Value: 'true' }, - { Name: 'sub', Value: '123-456789' } - ]); - }); - }); - - const spyon3 = jest.spyOn(Auth.prototype, 'currentCredentials').mockImplementationOnce(() => { - return Promise.resolve({ - identityId: 'identityId' - }); - }); - - const spyon4 = jest.spyOn(Credentials, 'getCredSource').mockImplementationOnce(() => { - return 'aws'; - }); - - expect.assertions(1); - expect(await auth.currentUserInfo()).toEqual({ - username: 'username', - id: 'identityId', - attributes: { - email: 'email', - phone_number: 'phone_number', - email_verified: false, - phone_number_verified: true, - sub: "123-456789" - } - }); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - spyon4.mockClear(); - }); - - test('return empty object if error happens', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(Auth.prototype, 'currentUserPoolUser') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res({ - username: 'username' - }); - }); - }); - - const spyon2 = jest.spyOn(Auth.prototype, 'userAttributes') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - const spyon3 = jest.spyOn(Auth.prototype, 'currentCredentials').mockImplementationOnce(() => { - return Promise.resolve({ - IdentityPoolId: 'identityPoolId', - identityId: 'identityId' - }); - }); - - const spyon4 = jest.spyOn(Credentials, 'getCredSource').mockImplementationOnce(() => { - return 'aws'; - }); - - expect.assertions(1); - expect(await auth.currentUserInfo()).toEqual({}); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - spyon4.mockClear(); - }); - - test('no current userpool user', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - auth['credentials_source'] = 'aws'; - - const spyon = jest.spyOn(Auth.prototype, 'currentUserPoolUser') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(null); - }); - }); - - const spyon2 = jest.spyOn(Credentials, 'getCredSource').mockImplementationOnce(() => { - return 'aws'; - }); - - expect.assertions(1); - expect(await auth.currentUserInfo()).toBeNull(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('federated user', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - auth['user'] = 'federated_user'; - - const spyon = jest.spyOn(Credentials, 'getCredSource').mockImplementationOnce(() => { - return 'federated'; - }); - - expect.assertions(1); - expect(await auth.currentUserInfo()).toBe('federated_user'); - - spyon.mockClear(); - }); - }); - - describe('updateUserAttributes test', () => { - test('happy case', async () => { - - const auth = new Auth(authOptions); - - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const attributes = { - 'email': 'email', - 'phone_number': 'phone_number', - 'sub': 'sub' - }; - - const spyon = jest.spyOn(Auth.prototype, 'userSession').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(session); - }); - }); - - expect.assertions(1); - expect(await auth.updateUserAttributes(user,attributes)).toBe('SUCCESS'); - - spyon.mockClear(); - }); - }); - - describe('federatedSignIn test', () => { - test('No Identity Pool and No User Pool', async () => { - const options : AuthOptions = { }; - - const auth = new Auth(options); - - let error; - try { - await auth.federatedSignIn( - 'google', - { token: 'token', expires_at: 1234 }, - { name: 'username' } - ); - }catch(e){ - error = e; - } - - expect(error).toEqual(new Error('Federation requires either a User Pool or Identity Pool in config')); - }); - - test('No User Pool', async () => { - const options : AuthOptions = { }; - - const auth = new Auth(options); - - let error; - try { - await auth.federatedSignIn(); - }catch(e){ - error = e; - } - - expect(error).toEqual(new Error('Federation requires either a User Pool or Identity Pool in config')); - }); - - test('Identity Pool Missing Tokens', async () => { - const options : AuthOptions = { - region: "region", - identityPoolId: "awsCognitoIdentityPoolId", - }; - - const auth = new Auth(options); - - let error; - try { - await auth.federatedSignIn(); - }catch(e){ - error = e; - } - - expect(error).toEqual(new Error('Federation with Identity Pools requires tokens passed as arguments')); - }); - - test('Identity Pools Only', async () => { - const options : AuthOptions = { - region: "region", - identityPoolId: "awsCognitoIdentityPoolId", - }; - - const auth = new Auth(options); - let user = null; - const spyon = jest.spyOn(Credentials, 'set').mockImplementationOnce(() => { - user = { name: 'username', email: 'xxx@email.com'}; - return Promise.resolve('cred'); - }); - const spyon2 = jest.spyOn(Auth.prototype, 'currentAuthenticatedUser').mockImplementation(() => { - if (!user) return Promise.reject('error'); - else return Promise.resolve(user); - }); - - - await auth.federatedSignIn('google', { token: 'token', expires_at: 1234 }, { name: 'username' }); - - expect(spyon).toBeCalled(); - expect(spyon2).toBeCalled(); - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('User Pools Only', async () => { - - const urlOpener = jest.fn(); - - const options : AuthOptions = { - region: "region", - userPoolId: 'userPoolId', - oauth: { - domain: 'mydomain.auth.us-east-1.amazoncognito.com', - scope: ['aws.cognito.signin.user.admin'], - redirectSignIn: 'http://localhost:3000/', - redirectSignOut: 'http://localhost:3000/', - responseType: 'code', - urlOpener - } - }; - - const auth = new Auth(options); - - const spyon3 = jest.spyOn(OAuth.prototype, 'oauthSignIn'); - - await auth.federatedSignIn(); - - expect(spyon3).toBeCalled(); - spyon3.mockClear(); - expect(urlOpener).toBeCalled(); - }); - - test('User Pools and Identity Pools', async () => { - - const urlOpener = jest.fn(); - - const options : AuthOptions = { - region: "region", - identityPoolId: "awsCognitoIdentityPoolId", - userPoolId: 'userPoolId', - oauth: { - domain: 'mydomain.auth.us-east-1.amazoncognito.com', - scope: ['aws.cognito.signin.user.admin'], - redirectSignIn: 'http://localhost:3000/', - redirectSignOut: 'http://localhost:3000/', - responseType: 'code', - urlOpener - } - }; - - const auth = new Auth(options); - - const spyon3 = jest.spyOn(OAuth.prototype, 'oauthSignIn'); - - let user = null; - const spyon = jest.spyOn(Credentials, 'set').mockImplementationOnce(() => { - user = { name: 'username', email: 'xxx@email.com'}; - return Promise.resolve('cred'); - }); - const spyon2 = jest.spyOn(Auth.prototype, 'currentAuthenticatedUser').mockImplementation(() => { - if (!user) return Promise.reject('error'); - else return Promise.resolve(user); - }); - - - await auth.federatedSignIn('google', { token: 'token', expires_at: 1234 }, { name: 'username' }); - - expect(spyon).toBeCalled(); - expect(spyon2).toBeCalled(); - spyon.mockClear(); - spyon2.mockClear(); - - expect(spyon3).not.toBeCalled(); - spyon3.mockClear(); - expect(urlOpener).not.toBeCalled(); - }); - - }); - - describe('handleAuthResponse test', () => { - beforeAll(() => { - jest.spyOn(Auth.prototype, 'currentAuthenticatedUser').mockImplementation(() => { - throw new Error('no user logged in'); - }); - }); - - test('User Pools Code Flow', async () => { - - const options : AuthOptions = { - region: "region", - userPoolId: 'userPoolId', - oauth: { - domain: 'mydomain.auth.us-east-1.amazoncognito.com', - scope: ['aws.cognito.signin.user.admin'], - redirectSignIn: 'http://localhost:3000/', - redirectSignOut: 'http://localhost:3000/', - responseType: 'code', - } - }; - - const auth = new Auth(options); - - const handleAuthResponseSpy = jest.spyOn(OAuth.prototype, 'handleAuthResponse') - .mockReturnValueOnce({ idToken: '' }); - jest.spyOn(CognitoUserSession.prototype, 'getIdToken').mockReturnValueOnce({ decodePayload: () => ({}) }); - jest.spyOn(Credentials, 'set').mockImplementationOnce(c => c); - (auth as any).createCognitoUser = jest.fn(() => ({ - getUsername: jest.fn(), - setSignInUserSession: jest.fn() - })); - const replaceStateSpy = jest.spyOn(window.history, 'replaceState').mockReturnThis(); - - const code = 'XXXX-YYY-ZZZ'; - const state = 'STATEABC'; - const url = `${(options.oauth as AwsCognitoOAuthOpts).redirectSignIn}?code=${code}&state=${state}`; - - (oauthStorage.getState as jest.Mock).mockReturnValueOnce(state); - await (auth as any)._handleAuthResponse(url); - - expect(handleAuthResponseSpy).toHaveBeenCalledWith(url); - expect(replaceStateSpy) - .toHaveBeenCalledWith({}, null, (options.oauth as AwsCognitoOAuthOpts).redirectSignIn); - }); - - test('User Pools Implicit Flow', async () => { - - const options : AuthOptions = { - region: "region", - userPoolId: 'userPoolId', - oauth: { - domain: 'mydomain.auth.us-east-1.amazoncognito.com', - scope: ['aws.cognito.signin.user.admin'], - redirectSignIn: 'http://localhost:3000/', - redirectSignOut: 'http://localhost:3000/', - responseType: 'token', - } - }; - - const auth = new Auth(options); - - const handleAuthResponseSpy = jest.spyOn(OAuth.prototype, 'handleAuthResponse') - .mockReturnValueOnce({ idToken: '' }); - jest.spyOn(CognitoUserSession.prototype, 'getIdToken').mockReturnValueOnce({ decodePayload: () => ({}) }); - jest.spyOn(Credentials, 'set').mockImplementationOnce(c => c); - (auth as any).createCognitoUser = jest.fn(() => ({ - getUsername: jest.fn(), - setSignInUserSession: jest.fn() - })); - const replaceStateSpy = jest.spyOn(window.history, 'replaceState').mockReturnThis(); - - const token = 'XXXX.YYY.ZZZ'; - const state = 'STATEABC'; - const url = `${(options.oauth as AwsCognitoOAuthOpts).redirectSignIn}#access_token=${token}&state=${state}`; - - await (auth as any)._handleAuthResponse(url); - - expect(handleAuthResponseSpy).toHaveBeenCalledWith(url); - expect(replaceStateSpy) - .toHaveBeenCalledWith({}, null, (options.oauth as AwsCognitoOAuthOpts).redirectSignIn); - }); - - test('No User Pools', async () => { - - const urlOpener = jest.fn(); - - const options : AuthOptions = {}; - - const auth = new Auth(options); - - let error; - try { - await (auth as any)._handleAuthResponse(' '); - }catch(e){ - error = e; - } - - expect(error).toEqual(new Error('OAuth responses require a User Pool defined in config')); - }); - - test('User Pools and Identity Pools', async () => { - const options : AuthOptions = { - region: "region", - userPoolId: 'userPoolId', - oauth: { - domain: 'mydomain.auth.us-east-1.amazoncognito.com', - scope: ['aws.cognito.signin.user.admin'], - redirectSignIn: 'http://localhost:3000/', - redirectSignOut: 'http://localhost:3000/', - responseType: 'code', - }, - identityPoolId: "awsCognitoIdentityPoolId", - }; - - const auth = new Auth(options); - - const handleAuthResponseSpy = jest.spyOn(OAuth.prototype, 'handleAuthResponse') - .mockReturnValueOnce({ idToken: '' }); - jest.spyOn(CognitoUserSession.prototype, 'getIdToken').mockReturnValueOnce({ decodePayload: () => ({}) }); - jest.spyOn(Credentials, 'set').mockImplementationOnce(c => c); - (auth as any).createCognitoUser = jest.fn(() => ({ - getUsername: jest.fn(), - setSignInUserSession: jest.fn() - })); - const replaceStateSpy = jest.spyOn(window.history, 'replaceState').mockReturnThis(); - - const code = 'XXXX-YYY-ZZZ'; - const url = `${(options.oauth as AwsCognitoOAuthOpts).redirectSignIn}?code=${code}`; - await (auth as any)._handleAuthResponse(url); - - expect(handleAuthResponseSpy).toHaveBeenCalledWith(url); - expect(replaceStateSpy) - .toHaveBeenCalledWith({}, null, (options.oauth as AwsCognitoOAuthOpts).redirectSignIn); - }); - }); - - describe('verifiedContact test', () => { - test('happy case with unverified', async () => { - const spyon = jest.spyOn(Auth.prototype, 'userAttributes') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res([{ - Name: 'email', - Value: 'email@amazon.com' - }, - { - Name: 'phone_number', - Value: '+12345678901' - }]); - }); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect(await auth.verifiedContact(user)).toEqual({ - "unverified": { "email": "email@amazon.com", "phone_number": "+12345678901" }, - "verified": {} - }); - - spyon.mockClear(); - }); - - test('happy case with unverified', async () => { - const spyon = jest.spyOn(Auth.prototype, 'userAttributes') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res([{ - Name: 'email', - Value: 'email@amazon.com' - }, - { - Name: 'phone_number', - Value: '+12345678901' - }, - { - Name: 'email_verified', - Value: true - }, - { - Name: 'phone_number_verified', - Value: true - }]); - }); - }); - - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - expect(await auth.verifiedContact(user)).toEqual({ - "unverified": {}, - "verified": { "email": "email@amazon.com", "phone_number": "+12345678901" } - }); - - spyon.mockClear(); - }); - }); - - describe('currentUserPoolUser test', () => { - test('happy case', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(CognitoUserPool.prototype, 'getCurrentUser') - .mockImplementation(() => { - return user; - }); - const spyon2 = jest.spyOn(CognitoUser.prototype, 'getSession') - .mockImplementation((callback) => { - return callback(null, session); - }); - - const spyon3 = jest.spyOn(CognitoUser.prototype, 'getUserData').mockImplementationOnce((callback) => { - const data = { - PreferredMfaSetting: 'SMS', - UserAttributes: [ - {Name: 'address', Value: 'xxxx'} - ] - }; - callback(null, data); - }); - - const spyon4 = jest.spyOn(CognitoUserSession.prototype, 'getAccessToken') - .mockImplementationOnce(() => { - return new CognitoAccessToken({AccessToken: 'accessToken'}); - }); - - const spyon5 = jest.spyOn(CognitoAccessToken.prototype, 'decodePayload') - .mockImplementation(() => { - return { scope: USER_ADMIN_SCOPE }; - }); - - expect.assertions(1); - expect(await auth.currentUserPoolUser()).toBe(Object.assign(user, { - attributes: { - address: 'xxxx' - }, - preferredMFA: 'SMS' - })); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - spyon4.mockClear(); - spyon5.mockClear(); - }); - - test('no current user', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(CognitoUserPool.prototype, 'getCurrentUser') - .mockImplementation(() => { - return null; - }); - - expect.assertions(1); - try { - await auth.currentUserPoolUser(); - } catch (e) { - expect(e).toBe('No current user'); - } - - spyon.mockClear(); - }); - - test('No userPool in config', async () => { - const auth = new Auth(authOptionsWithNoUserPoolId); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - const errorMessage = new NoUserPoolError(AuthErrorTypes.EmptyCode); - - expect.assertions(2); - expect(auth.currentUserPoolUser().then()).rejects.toThrow(NoUserPoolError); - expect(auth.currentUserPoolUser().then()).rejects.toEqual(errorMessage); - }); - - test('get session error', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(CognitoUserPool.prototype, 'getCurrentUser') - .mockImplementation(() => { - return user; - }); - const spyon2 = jest.spyOn(CognitoUser.prototype, 'getSession') - .mockImplementation((callback) => { - return callback('err', null); - }); - - const spyon3 = jest.spyOn(CognitoUser.prototype, 'getUserData'); - - expect.assertions(2); - try { - await auth.currentUserPoolUser(); - } catch (e) { - expect(e).toBe('err'); - expect(spyon3).not.toBeCalled(); - } - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - }); - - test('get user data error because of user is deleted or disabled', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(CognitoUserPool.prototype, 'getCurrentUser') - .mockImplementation(() => { - return user; - }); - const spyon2 = jest.spyOn(CognitoUser.prototype, 'getSession') - .mockImplementation((callback) => { - return callback(null, session); - }); - const spyon3 = jest.spyOn(CognitoUser.prototype, 'getUserData').mockImplementationOnce((callback) => { - callback({ - message: 'User is disabled' - }, null); - }); - - const spyon4 = jest.spyOn(CognitoUserSession.prototype, 'getAccessToken') - .mockImplementationOnce(() => { - return new CognitoAccessToken({AccessToken: 'accessToken'}); - }); - - const spyon5 = jest.spyOn(CognitoAccessToken.prototype, 'decodePayload') - .mockImplementation(() => { - return { scope: USER_ADMIN_SCOPE }; - }); - - expect.assertions(1); - try { - await auth.currentUserPoolUser(); - } catch (e) { - expect(e).toEqual({ - message: 'User is disabled' - }); - } - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - spyon4.mockClear(); - spyon5.mockClear(); - }); - - test('bypass the error if the user is not deleted or disabled', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(CognitoUserPool.prototype, 'getCurrentUser') - .mockImplementation(() => { - return user; - }); - const spyon2 = jest.spyOn(CognitoUser.prototype, 'getSession') - .mockImplementation((callback) => { - return callback(null, session); - }); - const spyon3 = jest.spyOn(CognitoUser.prototype, 'getUserData').mockImplementationOnce((callback) => { - callback({ - message: 'other error' - }, null); - }); - - const spyon4 = jest.spyOn(CognitoUserSession.prototype, 'getAccessToken') - .mockImplementationOnce(() => { - return new CognitoAccessToken({AccessToken: 'accessToken'}); - }); - - const spyon5 = jest.spyOn(CognitoAccessToken.prototype, 'decodePayload') - .mockImplementation(() => { - return { scope: USER_ADMIN_SCOPE }; - }); - - expect.assertions(1); - - expect(await auth.currentUserPoolUser()).toEqual(user); - - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - spyon4.mockClear(); - spyon5.mockClear(); - }); - - test('directly return the user if no permission(scope) to get the user data', async () => { - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - - const spyon = jest.spyOn(CognitoUserPool.prototype, 'getCurrentUser') - .mockImplementation(() => { - return user; - }); - const spyon2 = jest.spyOn(CognitoUser.prototype, 'getSession') - .mockImplementation((callback) => { - return callback(null, session); - }); - - const spyon3 = jest.spyOn(CognitoUser.prototype, 'getUserData').mockImplementationOnce((callback) => { - const data = { - PreferredMfaSetting: 'SMS', - UserAttributes: [ - {Name: 'address', Value: 'xxxx'} - ] - }; - callback(null, data); - }); - - const spyon4 = jest.spyOn(CognitoUserSession.prototype, 'getAccessToken') - .mockImplementationOnce(() => { - return new CognitoAccessToken({AccessToken: 'accessToken'}); - }); - - const spyon5 = jest.spyOn(CognitoAccessToken.prototype, 'decodePayload') - .mockImplementation(() => { - return { scope: '' }; - }); - - expect.assertions(2); - expect(spyon3).not.toBeCalled(); - expect(await auth.currentUserPoolUser()).toBe(user); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - spyon4.mockClear(); - spyon5.mockClear(); - }); - }); - - describe('sendCustomChallengeAnswer', () => { - test('happy case', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'sendCustomChallengeAnswer') - .mockImplementationOnce((challengeResponses, callback) => { - callback.onSuccess(session); - }); - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - const userAfterCustomChallengeAnswer = Object.assign( - new CognitoUser({ - Username: 'username', - Pool: userPool - }), - { - "challengeName": "CUSTOM_CHALLENGE", - "challengeParam": "challengeParam" - }); - - const spyon2 = jest.spyOn(auth, 'currentUserPoolUser').mockImplementationOnce(() => { - return Promise.resolve(user); - }); - - expect.assertions(1); - expect(await auth.sendCustomChallengeAnswer(userAfterCustomChallengeAnswer, 'challengeResponse')).toEqual(user); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('customChallenge', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'sendCustomChallengeAnswer') - .mockImplementationOnce((challengeResponses, callback) => { - callback.customChallenge('challengeParam'); - }); - const auth = new Auth(authOptions); - const user = new CognitoUser({ - Username: 'username', - Pool: userPool - }); - const userAfterCustomChallengeAnswer = Object.assign( - new CognitoUser({ - Username: 'username', - Pool: userPool - }), - { - "challengeName": "CUSTOM_CHALLENGE", - "challengeParam": "challengeParam" - }); - - expect.assertions(1); - expect(await auth.sendCustomChallengeAnswer(userAfterCustomChallengeAnswer, 'challengeResponse')).toEqual(userAfterCustomChallengeAnswer); - - spyon.mockClear(); - }); - - test('onFailure', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'sendCustomChallengeAnswer') - .mockImplementationOnce((challengeResponses, callback) => { - callback.onFailure('err'); - }); - - const auth = new Auth(authOptions); - const userAfterCustomChallengeAnswer = Object.assign( - new CognitoUser({ - Username: 'username', - Pool: userPool - }), - { - "challengeName": "CUSTOM_CHALLENGE", - "challengeParam": "challengeParam" - }); - - expect.assertions(1); - try { - await auth.sendCustomChallengeAnswer(userAfterCustomChallengeAnswer, 'challengeResponse'); - } catch (e) { - expect(e).toBe('err'); - } - - spyon.mockClear(); - }); - - test('no userPool', async () => { - const spyon = jest.spyOn(CognitoUser.prototype, 'sendCustomChallengeAnswer'); - - const auth = new Auth(authOptionsWithNoUserPoolId); - const userAfterCustomChallengeAnswer = Object.assign( - new CognitoUser({ - Username: 'username', - Pool: userPool - }), - { - "challengeName": "CUSTOM_CHALLENGE", - "challengeParam": "challengeParam" - }); - const errorMessage = new NoUserPoolError(AuthErrorTypes.MissingAuthConfig); - - expect.assertions(2); - expect(auth.sendCustomChallengeAnswer(userAfterCustomChallengeAnswer, 'challengeResponse') - .then()).rejects.toThrow(AuthError); - - expect(auth.sendCustomChallengeAnswer(userAfterCustomChallengeAnswer, 'challengeResponse') - .then()).rejects.toEqual(errorMessage); - - spyon.mockClear(); - }); - }); + describe('signUp', () => { + test('happy case with object attr', async () => { + const spyon = jest.spyOn(CognitoUserPool.prototype, 'signUp'); + const auth = new Auth(authOptions); + + const attrs = { + username: 'username', + password: 'password', + attributes: { + email: 'email', + phone_number: 'phone_number', + otherAttrs: 'otherAttrs', + }, + }; + + expect(await auth.signUp(attrs)).toBe('signUpResult'); + + spyon.mockClear(); + }); + + test('object attr with null username', async () => { + const auth = new Auth(authOptions); + + const attrs = { + username: null, + password: 'password', + attributes: { + email: 'email', + phone_number: 'phone_number', + otherAttrs: 'otherAttrs', + }, + }; + expect.assertions(1); + expect(auth.signUp(attrs).then()).rejects.toThrow(AuthError); + }); + + test('callback error', async () => { + const spyon = jest + .spyOn(CognitoUserPool.prototype, 'signUp') + .mockImplementationOnce( + ( + username, + password, + signUpAttributeList, + validationData, + callback + ) => { + callback('err', null); + } + ); + + const auth = new Auth(authOptions); + + expect.assertions(1); + try { + const attrs = { + username: 'username', + password: 'password', + attributes: { + email: 'email', + phone_number: 'phone_number', + otherAttrs: 'otherAttrs', + }, + }; + await auth.signUp(attrs); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + + test('no config', async () => { + const auth = new Auth(undefined); + const errorMessage = new NoUserPoolError(AuthErrorTypes.NoConfig); + + expect.assertions(2); + expect( + auth.signUp('username', 'password', 'email', 'phone').then() + ).rejects.toThrow(NoUserPoolError); + expect( + auth.signUp('username', 'password', 'email', 'phone').then() + ).rejects.toEqual(errorMessage); + }); + + test('no user pool in config', async () => { + const auth = new Auth(authOptionsWithNoUserPoolId); + const errorMessage = new NoUserPoolError( + AuthErrorTypes.MissingAuthConfig + ); + + expect.assertions(2); + expect( + auth.signUp('username', 'password', 'email', 'phone').then() + ).rejects.toThrow(NoUserPoolError); + expect( + auth.signUp('username', 'password', 'email', 'phone').then() + ).rejects.toEqual(errorMessage); + }); + + test('no username', async () => { + const auth = new Auth(authOptions); + expect.assertions(1); + expect( + auth.signUp(null, 'password', 'email', 'phone').then() + ).rejects.toThrow(AuthError); + }); + + test('no password', async () => { + const auth = new Auth(authOptions); + const errorMessage = new AuthError(AuthErrorTypes.EmptyPassword); + + expect.assertions(2); + expect( + auth.signUp('username', null, 'email', 'phone').then() + ).rejects.toThrow(AuthError); + expect( + auth.signUp('username', null, 'email', 'phone').then() + ).rejects.toEqual(errorMessage); + }); + + test('only username', async () => { + const auth = new Auth(authOptions); + const errorMessage = new AuthError(AuthErrorTypes.EmptyPassword); + + expect.assertions(2); + expect(auth.signUp('username').then()).rejects.toThrow(AuthError); + expect(auth.signUp('username').then()).rejects.toEqual(errorMessage); + }); + }); + + describe('confirmSignUp', () => { + test('happy case', async () => { + const spyon = jest.spyOn(CognitoUser.prototype, 'confirmRegistration'); + const auth = new Auth(authOptions); + + expect.assertions(1); + expect(await auth.confirmSignUp('username', 'code')).toBe('Success'); + + spyon.mockClear(); + }); + + test('with options', async () => { + const spyon = jest.spyOn(CognitoUser.prototype, 'confirmRegistration'); + const auth = new Auth(authOptions); + + expect.assertions(1); + expect( + await auth.confirmSignUp('username', 'code', { + forceAliasCreation: false, + }) + ).toBe('Success'); + + spyon.mockClear(); + }); + + test('callback err', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'confirmRegistration') + .mockImplementationOnce( + (confirmationCode, forceAliasCreation, callback) => { + callback('err', null); + } + ); + + const auth = new Auth(authOptions); + + expect.assertions(1); + try { + await auth.confirmSignUp('username', 'code'); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + + test('no user pool in config', async () => { + const auth = new Auth(authOptionsWithNoUserPoolId); + const errorMessage = new NoUserPoolError( + AuthErrorTypes.MissingAuthConfig + ); + + expect.assertions(2); + expect(auth.confirmSignUp('username', 'code').then()).rejects.toThrow( + NoUserPoolError + ); + expect(auth.confirmSignUp('username', 'code').then()).rejects.toEqual( + errorMessage + ); + }); + + test('no user name', async () => { + const auth = new Auth(authOptions); + const errorMessage = new AuthError(AuthErrorTypes.EmptyUsername); + + expect.assertions(2); + expect(auth.confirmSignUp(null, 'code').then()).rejects.toThrow( + AuthError + ); + expect(auth.confirmSignUp(null, 'code').then()).rejects.toEqual( + errorMessage + ); + }); + + test('no code', async () => { + const auth = new Auth(authOptions); + const errorMessage = new AuthError(AuthErrorTypes.EmptyCode); + + expect.assertions(2); + expect(auth.confirmSignUp('username', null).then()).rejects.toThrow( + AuthError + ); + expect(auth.confirmSignUp('username', null).then()).rejects.toEqual( + errorMessage + ); + }); + }); + + describe('resendSignUp', () => { + test('happy case', async () => { + const spyon = jest.spyOn(CognitoUser.prototype, 'resendConfirmationCode'); + const auth = new Auth(authOptions); + + expect.assertions(1); + expect(await auth.resendSignUp('username')).toBe('result'); + + spyon.mockClear(); + }); + + test('callback err', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'resendConfirmationCode') + .mockImplementationOnce(callback => { + callback('err', null); + }); + + const auth = new Auth(authOptions); + + expect.assertions(1); + try { + await auth.resendSignUp('username'); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + + test('no user pool in config', async () => { + const auth = new Auth(authOptionsWithNoUserPoolId); + const errorMessage = new NoUserPoolError( + AuthErrorTypes.MissingAuthConfig + ); + + expect.assertions(2); + expect(auth.resendSignUp('username').then()).rejects.toThrow( + NoUserPoolError + ); + expect(auth.resendSignUp('username').then()).rejects.toEqual( + errorMessage + ); + }); + + test('no username', async () => { + const auth = new Auth(authOptions); + const errorMessage = new AuthError(AuthErrorTypes.EmptyUsername); + + expect.assertions(2); + expect(auth.resendSignUp(null).then()).rejects.toThrow(AuthError); + expect(auth.resendSignUp(null).then()).rejects.toEqual(errorMessage); + }); + }); + + describe('signIn', () => { + test('happy case with password', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'authenticateUser') + .mockImplementationOnce((authenticationDetails, callback) => { + callback.onSuccess(session); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon2 = jest + .spyOn(auth, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return Promise.resolve(user); + }); + + expect.assertions(2); + expect(await auth.signIn('username', 'password')).toEqual(user); + expect(spyon2).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('throw error if failed to call currentUserPoolUser after signing in', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'authenticateUser') + .mockImplementationOnce((authenticationDetails, callback) => { + callback.onSuccess(session); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon2 = jest + .spyOn(auth, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return Promise.reject('User is disabled'); + }); + expect.assertions(2); + try { + await auth.signIn('username', 'password'); + } catch (e) { + expect(e).toBe('User is disabled'); + expect(spyon2).toBeCalled(); + } + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('happy case using cookie storage', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'authenticateUser') + .mockImplementationOnce((_authenticationDetails, callback) => { + callback.onSuccess(session); + }); + + const auth = new Auth({ + ...authOptions, + cookieStorage: { domain: '.example.com' }, + }); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + Storage: new CookieStorage({ domain: '.yourdomain.com' }), + }); + + const spyon2 = jest + .spyOn(auth, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return Promise.resolve(user); + }); + + expect.assertions(1); + expect(await auth.signIn('username', 'password')).toEqual(user); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('onFailure', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'authenticateUser') + .mockImplementationOnce((authenticationDetails, callback) => { + callback.onFailure('err'); + }); + + const auth = new Auth(authOptions); + + expect.assertions(1); + try { + await auth.signIn('username', 'password'); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + + test('mfaRequired', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'authenticateUser') + .mockImplementationOnce((authenticationDetails, callback) => { + callback.mfaRequired('challengeName', 'challengeParam'); + }); + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + const userAfterSignedIn = Object.assign({}, user, { + challengeName: 'challengeName', + challengeParam: 'challengeParam', + }); + + expect.assertions(1); + expect(await auth.signIn('username', 'password')).toEqual( + userAfterSignedIn + ); + + spyon.mockClear(); + }); + + test('mfaSetup', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'authenticateUser') + .mockImplementationOnce((authenticationDetails, callback) => { + callback.mfaSetup('challengeName', 'challengeParam'); + }); + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + const userAfterSignedIn = Object.assign({}, user, { + challengeName: 'challengeName', + challengeParam: 'challengeParam', + }); + + expect.assertions(1); + expect(await auth.signIn('username', 'password')).toEqual( + userAfterSignedIn + ); + + spyon.mockClear(); + }); + + test('totpRequired', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'authenticateUser') + .mockImplementationOnce((authenticationDetails, callback) => { + callback.totpRequired('challengeName', 'challengeParam'); + }); + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + const userAfterSignedIn = Object.assign({}, user, { + challengeName: 'challengeName', + challengeParam: 'challengeParam', + }); + + expect.assertions(1); + expect(await auth.signIn('username', 'password')).toEqual( + userAfterSignedIn + ); + + spyon.mockClear(); + }); + + test('selectMFAType', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'authenticateUser') + .mockImplementationOnce((authenticationDetails, callback) => { + callback.selectMFAType('challengeName', 'challengeParam'); + }); + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + const userAfterSignedIn = Object.assign({}, user, { + challengeName: 'challengeName', + challengeParam: 'challengeParam', + }); + + expect.assertions(1); + expect(await auth.signIn('username', 'password')).toEqual( + userAfterSignedIn + ); + + spyon.mockClear(); + }); + + test('newPasswordRequired', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'authenticateUser') + .mockImplementationOnce((authenticationDetails, callback) => { + callback.newPasswordRequired('userAttributes', 'requiredAttributes'); + }); + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + const userAfterSignedIn = Object.assign({}, user, { + challengeName: 'NEW_PASSWORD_REQUIRED', + challengeParam: { + requiredAttributes: 'requiredAttributes', + userAttributes: 'userAttributes', + }, + }); + + expect.assertions(1); + expect(await auth.signIn('username', 'password')).toEqual( + userAfterSignedIn + ); + + spyon.mockClear(); + }); + + test('customChallenge', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'authenticateUser') + .mockImplementationOnce((authenticationDetails, callback) => { + callback.customChallenge('challengeParam'); + }); + const spyon2 = jest + .spyOn(CognitoUser.prototype, 'setAuthenticationFlowType') + .mockImplementationOnce(type => {}); + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + const userAfterSignedIn = Object.assign({}, user, { + challengeName: 'CUSTOM_CHALLENGE', + challengeParam: 'challengeParam', + }); + + expect.assertions(2); + expect(await auth.signIn('username')).toEqual(userAfterSignedIn); + expect(spyon2).toBeCalledWith('CUSTOM_AUTH'); + + spyon2.mockClear(); + spyon.mockClear(); + }); + + test('no userPool', async () => { + const spyon = jest.spyOn(CognitoUser.prototype, 'authenticateUser'); + + // @ts-ignore + const auth = new Auth(authOptionsWithNoUserPoolId); + + expect.assertions(1); + try { + await auth.signIn('username', 'password'); + } catch (e) { + expect(e).not.toBeNull(); + } + + spyon.mockClear(); + }); + + test('no username', async () => { + const spyon = jest.spyOn(CognitoUser.prototype, 'authenticateUser'); + const auth = new Auth(authOptions); + + expect.assertions(1); + try { + await auth.signIn(null, 'password'); + } catch (e) { + expect(e).not.toBeNull(); + } + + spyon.mockClear(); + }); + }); + + describe('confirmSignIn', () => { + test('happy case', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'sendMFACode') + .mockImplementationOnce((code, callback) => { + callback.onSuccess(session); + }); + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + expect(await auth.confirmSignIn(user, 'code', null)).toEqual(user); + + spyon.mockClear(); + }); + + test('onFailure', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'sendMFACode') + .mockImplementationOnce((code, callback) => { + callback.onFailure('err'); + }); + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + try { + await auth.confirmSignIn(user, 'code', null); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + + test('no code', async () => { + const spyon = jest.spyOn(CognitoUser.prototype, 'sendMFACode'); + const auth = new Auth(authOptions); + + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + try { + await auth.confirmSignIn(user, null, null); + } catch (e) { + expect(e).not.toBeNull(); + } + + spyon.mockClear(); + }); + }); + + describe('completeNewPassword', () => { + test('happy case', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'completeNewPasswordChallenge') + .mockImplementationOnce((password, requiredAttributes, callback) => { + callback.onSuccess(session); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + expect(await auth.completeNewPassword(user, 'password', {})).toEqual( + user + ); + + spyon.mockClear(); + }); + + test('on Failure', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'completeNewPasswordChallenge') + .mockImplementationOnce((password, requiredAttributes, callback) => { + callback.onFailure('err'); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + try { + await auth.completeNewPassword(user, 'password', {}); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + + test('mfaRequired', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'completeNewPasswordChallenge') + .mockImplementationOnce((password, requiredAttributes, callback) => { + callback.mfaRequired('challengeName', 'challengeParam'); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + expect(await auth.completeNewPassword(user, 'password', {})).toBe(user); + + spyon.mockClear(); + }); + + test('mfaSetup', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'completeNewPasswordChallenge') + .mockImplementationOnce((password, requiredAttributes, callback) => { + callback.mfaSetup('challengeName', 'challengeParam'); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + expect(await auth.completeNewPassword(user, 'password', {})).toBe(user); + + spyon.mockClear(); + }); + + test('no password', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const errorMessage = new AuthError(AuthErrorTypes.EmptyPassword); + + expect.assertions(2); + await expect( + auth.completeNewPassword(user, null, {}).then() + ).rejects.toThrow(AuthError); + await expect( + auth.completeNewPassword(user, null, {}).then() + ).rejects.toEqual(errorMessage); + }); + }); + + describe('userAttributes', () => { + test('happy case', async () => { + const spyon = jest + .spyOn(Auth.prototype, 'userSession') + .mockImplementationOnce(user => { + return new Promise((res, rej) => { + res('session'); + }); + }); + + const spyon2 = jest.spyOn(CognitoUser.prototype, 'getUserAttributes'); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + expect(await auth.userAttributes(user)).toBe('attributes'); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('get userattributes failed', async () => { + const spyon = jest + .spyOn(Auth.prototype, 'userSession') + .mockImplementationOnce(user => { + return new Promise((res, rej) => { + res('session'); + }); + }); + + const spyon2 = jest + .spyOn(CognitoUser.prototype, 'getUserAttributes') + .mockImplementationOnce(callback => { + callback('err'); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + try { + await auth.userAttributes(user); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); + + describe('currentSession', () => { + test('happy case', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(auth, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return Promise.resolve(user); + }); + + const spyon2 = jest + .spyOn(Auth.prototype, 'userSession') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(session); + }); + }); + expect.assertions(1); + expect(await auth.currentSession()).toEqual(session); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('no current session', async () => { + const auth = new Auth(authOptions); + + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(auth, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return Promise.resolve(user); + }); + + const spyon2 = jest + .spyOn(auth, 'userSession') + .mockImplementationOnce(() => { + return Promise.reject('cannot get the session'); + }); + + expect.assertions(1); + try { + await auth.currentSession(); + } catch (e) { + expect(e).toBe('cannot get the session'); + } + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('no current user', async () => { + const auth = new Auth(authOptions); + + const spyon = jest + .spyOn(auth, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return Promise.reject('no current user'); + }); + + expect.assertions(1); + try { + await auth.currentSession(); + } catch (e) { + expect(e).toBe('no current user'); + } + + spyon.mockClear(); + }); + + test('no UserPool', async () => { + const auth = new Auth({ + userPoolId: undefined, + userPoolWebClientId: 'awsUserPoolsWebClientId', + region: 'region', + identityPoolId: 'awsCognitoIdentityPoolId', + mandatorySignIn: false, + }); + const errorMessage = new NoUserPoolError( + AuthErrorTypes.MissingAuthConfig + ); + + expect.assertions(2); + expect(auth.currentSession().then()).rejects.toThrow(NoUserPoolError); + expect(auth.currentSession().then()).rejects.toEqual(errorMessage); + }); + }); + + describe('currentAuthenticatedUser', () => { + test('happy case with source userpool', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(Auth.prototype, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(user); + }); + }); + expect.assertions(1); + expect(await auth.currentAuthenticatedUser()).toEqual(user); + + spyon.mockClear(); + }); + + test('happy case with source federation', async () => { + const spyon = jest + .spyOn(StorageHelper.prototype, 'getStorage') + .mockImplementation(() => { + return { + getItem() { + return JSON.stringify({ + user: 'federated_user', + }); + }, + }; + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + expect(await auth.currentAuthenticatedUser()).toBe('federated_user'); + + spyon.mockClear(); + }); + }); + + describe('userSession test', () => { + test('happy case', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'getSession') + .mockImplementationOnce(callback => { + callback(null, session); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + expect(await auth.userSession(user)).toEqual(session); + + spyon.mockClear(); + }); + + test('callback error', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(CognitoUser.prototype, 'getSession') + .mockImplementationOnce(callback => { + callback('err', null); + }); + + expect.assertions(1); + try { + await auth.userSession(user); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + + test('no user', async () => { + const auth = new Auth(authOptions); + const user = null; + + expect.assertions(1); + try { + await auth.userSession(user); + } catch (e) { + expect(e).not.toBeNull(); + } + }); + }); + + describe('currentUserCredentials test', () => { + test('with federated info', async () => { + const spyon = jest + .spyOn(StorageHelper.prototype, 'getStorage') + .mockImplementation(() => { + return { + getItem() { + return JSON.stringify({ + provider: 'google', + token: 'token', + }); + }, + }; + }); + + const auth = new Auth(authOptions); + + const spyon2 = jest + .spyOn(Credentials, 'refreshFederatedToken') + .mockImplementationOnce(() => { + return Promise.resolve('cred'); + }); + + expect.assertions(1); + expect(await auth.currentUserCredentials()).toBe('cred'); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('with cognito session', async () => { + const spyon = jest + .spyOn(StorageHelper.prototype, 'getStorage') + .mockImplementation(() => { + return { + getItem() { + return null; + }, + }; + }); + const auth = new Auth(authOptions); + + const spyon2 = jest + .spyOn(auth, 'currentSession') + .mockImplementationOnce(() => { + return Promise.resolve('session'); + }); + + const spyon3 = jest + .spyOn(Credentials, 'set') + .mockImplementationOnce(() => { + return Promise.resolve('cred'); + }); + + expect.assertions(1); + expect(await auth.currentUserCredentials()).toBe('cred'); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + }); + + test('with guest', async () => { + const spyon = jest + .spyOn(StorageHelper.prototype, 'getStorage') + .mockImplementation(() => { + return { + getItem() { + return null; + }, + }; + }); + const auth = new Auth(authOptions); + + const spyon2 = jest + .spyOn(auth, 'currentSession') + .mockImplementationOnce(() => { + return Promise.reject('err'); + }); + + const spyon3 = jest + .spyOn(Credentials, 'set') + .mockImplementationOnce(() => { + return Promise.resolve('cred'); + }); + + expect.assertions(1); + expect(await auth.currentUserCredentials()).toBe('cred'); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + }); + + test('json parse error', async () => { + const spyon = jest + .spyOn(StorageHelper.prototype, 'getStorage') + .mockImplementation(() => { + return { + getItem() { + return undefined; + }, + }; + }); + const auth = new Auth(authOptions); + + const spyon2 = jest + .spyOn(auth, 'currentSession') + .mockImplementationOnce(() => { + return Promise.resolve('session'); + }); + + const spyon3 = jest + .spyOn(Credentials, 'set') + .mockImplementationOnce(() => { + return Promise.resolve('cred'); + }); + + expect.assertions(1); + expect(await auth.currentUserCredentials()).toBe('cred'); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + }); + }); + + describe('currentCrendentials', () => { + const spyon = jest.spyOn(Credentials, 'get').mockImplementationOnce(() => { + return; + }); + + const auth = new Auth(authOptions); + + auth.currentCredentials(); + expect(spyon).toBeCalled(); + spyon.mockClear(); + }); + + describe('verifyUserAttribute test', () => { + test('happy case', async () => { + const spyon = jest.spyOn( + CognitoUser.prototype, + 'getAttributeVerificationCode' + ); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + await auth.verifyUserAttribute(user, { email: 'xxx@xxx.com' }); + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + + test('onFailure', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'getAttributeVerificationCode') + .mockImplementationOnce((attr, callback) => { + callback.onFailure('err'); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + try { + await auth.verifyUserAttribute(user, {}); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + }); + + describe('verifyUserAttributeSubmit', () => { + test('happy case', async () => { + const spyon = jest.spyOn(CognitoUser.prototype, 'verifyAttribute'); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + expect(await auth.verifyUserAttributeSubmit(user, {}, 'code')).toBe( + 'success' + ); + + spyon.mockClear(); + }); + + test('onFailure', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'verifyAttribute') + .mockImplementationOnce((attr, code, callback) => { + callback.onFailure('err'); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect.assertions(1); + try { + await auth.verifyUserAttributeSubmit(user, {}, 'code'); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + + test('code empty', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + const errorMessage = new AuthError(AuthErrorTypes.EmptyCode); + + expect.assertions(2); + expect( + auth.verifyUserAttributeSubmit(user, {}, null).then() + ).rejects.toThrow(AuthError); + expect( + auth.verifyUserAttributeSubmit(user, {}, null).then() + ).rejects.toEqual(errorMessage); + }); + }); + + describe('verifyCurrentUserAttribute test', () => { + test('happy case', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(Auth.prototype, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(user); + }); + }); + + const spyon2 = jest + .spyOn(Auth.prototype, 'verifyUserAttribute') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(); + }); + }); + + await auth.verifyCurrentUserAttribute('attr'); + + expect.assertions(2); + expect(spyon).toBeCalled(); + expect(spyon2).toBeCalledWith(user, 'attr'); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); + + describe('verifyCurrentUserAttributeSubmit test', () => { + test('happy case', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(Auth.prototype, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(user); + }); + }); + + const spyon2 = jest + .spyOn(Auth.prototype, 'verifyUserAttributeSubmit') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(); + }); + }); + + await auth.verifyCurrentUserAttributeSubmit('attr', 'code'); + + expect.assertions(2); + expect(spyon).toBeCalled(); + expect(spyon2).toBeCalledWith(user, 'attr', 'code'); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); + + describe('signOut test', () => { + test('happy case', async () => { + const auth = new Auth(authOptions); + + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(Credentials, 'clear') + .mockImplementationOnce(() => { + return; + }); + const spyon2 = jest + .spyOn(CognitoUserPool.prototype, 'getCurrentUser') + .mockImplementationOnce(() => { + return user; + }); + + await auth.signOut(); + + expect.assertions(2); + expect(spyon).toBeCalled(); + expect(spyon2).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('happy case for source userpool', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + auth['credentials_source'] = 'aws'; + auth['credentials'] = new CognitoIdentityCredentials({ + IdentityPoolId: 'identityPoolId', + }); + + const spyonAuth = jest + .spyOn(Auth.prototype, 'currentUserCredentials') + .mockImplementationOnce(() => { + return new Promise((resolve, reject) => { + resolve(); + }); + }); + const spyon = jest + .spyOn(CognitoUserPool.prototype, 'getCurrentUser') + .mockImplementationOnce(() => { + return user; + }); + const spyon2 = jest.spyOn(CognitoUser.prototype, 'signOut'); + // @ts-ignore + + await auth.signOut(); + + expect.assertions(1); + expect(spyon2).toBeCalled(); + + spyonAuth.mockClear(); + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('happy case for globalSignOut', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyonAuth = jest + .spyOn(Credentials, 'clear') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + const spyon = jest + .spyOn(CognitoUserPool.prototype, 'getCurrentUser') + .mockImplementationOnce(() => { + return user; + }); + const spyon2 = jest.spyOn(CognitoUser.prototype, 'globalSignOut'); + + await auth.signOut({ global: true }); + + expect.assertions(1); + expect(spyon2).toBeCalled(); + + spyonAuth.mockClear(); + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('happy case for no userpool', async () => { + // @ts-ignore + const auth = new Auth(authOptionsWithNoUserPoolId); + + expect(await auth.signOut()).toBeUndefined(); + }); + + test('no User in userpool', async () => { + const auth = new Auth(authOptions); + + const spyon = jest + .spyOn(CognitoUserPool.prototype, 'getCurrentUser') + .mockImplementationOnce(() => { + return null; + }); + expect(await auth.signOut()).toBeUndefined(); + + spyon.mockClear(); + }); + + test('get guest credentials failed', async () => { + const auth = new Auth(authOptionsWithNoUserPoolId); + + const cognitoCredentialSpyon = jest + .spyOn(CognitoIdentityCredentials.prototype, 'get') + .mockImplementation(callback => { + callback(null); + }); + + expect(await auth.signOut()).toBeUndefined(); + + cognitoCredentialSpyon.mockClear(); + }); + }); + + describe('changePassword', () => { + test('happy case', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + const oldPassword = 'oldPassword1'; + const newPassword = 'newPassword1.'; + + const spyon = jest + .spyOn(Auth.prototype, 'userSession') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(session); + }); + }); + + expect.assertions(1); + expect(await auth.changePassword(user, oldPassword, newPassword)).toBe( + 'SUCCESS' + ); + + spyon.mockClear(); + }); + }); + + describe('forgotPassword', () => { + test('happy case', async () => { + const spyon = jest.spyOn(CognitoUser.prototype, 'forgotPassword'); + + const auth = new Auth(authOptions); + + expect.assertions(1); + expect(await auth.forgotPassword('username')).toBeUndefined(); + + spyon.mockClear(); + }); + + test('onFailue', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'forgotPassword') + .mockImplementationOnce(callback => { + callback.onFailure('err'); + }); + + const auth = new Auth(authOptions); + + expect.assertions(1); + try { + await auth.forgotPassword('username'); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + + test('inputVerficationCode', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'forgotPassword') + .mockImplementationOnce(callback => { + callback.inputVerificationCode('data'); + }); + + const auth = new Auth(authOptions); + + expect.assertions(1); + expect(await auth.forgotPassword('username')).toBe('data'); + + spyon.mockClear(); + }); + + test('no user pool id', async () => { + const spyon = jest.spyOn(CognitoUser.prototype, 'forgotPassword'); + + const auth = new Auth(authOptionsWithNoUserPoolId); + const errorMessage = new NoUserPoolError( + AuthErrorTypes.MissingAuthConfig + ); + + expect.assertions(2); + expect(auth.forgotPassword('username').then()).rejects.toThrow( + NoUserPoolError + ); + expect(auth.forgotPassword('username').then()).rejects.toEqual( + errorMessage + ); + + spyon.mockClear(); + }); + + test('no username', async () => { + const spyon = jest.spyOn(CognitoUser.prototype, 'forgotPassword'); + + const auth = new Auth(authOptions); + + expect.assertions(1); + try { + await auth.forgotPassword(null); + } catch (e) { + expect(e).not.toBeNull(); + } + spyon.mockClear(); + }); + }); + + describe('forgotPasswordSubmit', () => { + test('happy case', async () => { + const spyon = jest.spyOn(CognitoUser.prototype, 'confirmPassword'); + + const auth = new Auth(authOptions); + + expect.assertions(1); + expect( + await auth.forgotPasswordSubmit('username', 'code', 'password') + ).toBeUndefined(); + + spyon.mockClear(); + }); + + test('confirmPassword failed', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'confirmPassword') + .mockImplementationOnce((code, password, callback) => { + callback.onFailure('err'); + }); + + const auth = new Auth(authOptions); + + expect.assertions(1); + try { + await auth.forgotPasswordSubmit('username', 'code', 'password'); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + + test('no user pool in config', async () => { + const auth = new Auth(authOptionsWithNoUserPoolId); + const errorMessage = new NoUserPoolError( + AuthErrorTypes.MissingAuthConfig + ); + + expect.assertions(2); + expect( + auth.forgotPasswordSubmit('username', 'code', 'password').then() + ).rejects.toThrow(NoUserPoolError); + expect( + auth.forgotPasswordSubmit('username', 'code', 'password').then() + ).rejects.toEqual(errorMessage); + }); + + test('no username', async () => { + const auth = new Auth(authOptions); + const errorMessage = new AuthError(AuthErrorTypes.EmptyUsername); + + expect.assertions(2); + expect( + auth.forgotPasswordSubmit(null, 'code', 'password').then() + ).rejects.toThrow(AuthError); + expect( + auth.forgotPasswordSubmit(null, 'code', 'password').then() + ).rejects.toEqual(errorMessage); + }); + + test('no code', async () => { + const auth = new Auth(authOptions); + const errorMessage = new AuthError(AuthErrorTypes.EmptyCode); + + expect.assertions(2); + expect( + auth.forgotPasswordSubmit('username', null, 'password').then() + ).rejects.toThrow(AuthError); + expect( + auth.forgotPasswordSubmit('username', null, 'password').then() + ).rejects.toEqual(errorMessage); + }); + + test('no password', async () => { + const auth = new Auth(authOptions); + const errorMessage = new AuthError(AuthErrorTypes.EmptyPassword); + + expect.assertions(2); + expect( + auth.forgotPasswordSubmit('username', 'code', null).then() + ).rejects.toThrow(AuthError); + expect( + auth.forgotPasswordSubmit('username', 'code', null).then() + ).rejects.toEqual(errorMessage); + }); + }); + + describe('currentUserInfo test', () => { + test('happy case with aws or userpool source', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(Auth.prototype, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(user); + }); + }); + + const spyon2 = jest + .spyOn(Auth.prototype, 'userAttributes') + .mockImplementationOnce(() => { + auth['credentials'] = new CognitoIdentityCredentials({ + IdentityPoolId: 'identityPoolId', + IdentityId: 'identityId', + }); + auth['credentials']['identityId'] = 'identityId'; + return new Promise((res, rej) => { + res([ + { Name: 'email', Value: 'email' }, + { Name: 'phone_number', Value: 'phone_number' }, + { Name: 'email_verified', Value: 'false' }, + { Name: 'phone_number_verified', Value: 'true' }, + { Name: 'sub', Value: '123-456789' }, + ]); + }); + }); + + const spyon3 = jest + .spyOn(Auth.prototype, 'currentCredentials') + .mockImplementationOnce(() => { + return Promise.resolve({ + identityId: 'identityId', + }); + }); + + const spyon4 = jest + .spyOn(Credentials, 'getCredSource') + .mockImplementationOnce(() => { + return 'aws'; + }); + + expect.assertions(1); + expect(await auth.currentUserInfo()).toEqual({ + username: 'username', + id: 'identityId', + attributes: { + email: 'email', + phone_number: 'phone_number', + email_verified: false, + phone_number_verified: true, + sub: '123-456789', + }, + }); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + spyon4.mockClear(); + }); + + test('return empty object if error happens', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(Auth.prototype, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res({ + username: 'username', + }); + }); + }); + + const spyon2 = jest + .spyOn(Auth.prototype, 'userAttributes') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + const spyon3 = jest + .spyOn(Auth.prototype, 'currentCredentials') + .mockImplementationOnce(() => { + return Promise.resolve({ + IdentityPoolId: 'identityPoolId', + identityId: 'identityId', + }); + }); + + const spyon4 = jest + .spyOn(Credentials, 'getCredSource') + .mockImplementationOnce(() => { + return 'aws'; + }); + + expect.assertions(1); + expect(await auth.currentUserInfo()).toEqual({}); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + spyon4.mockClear(); + }); + + test('no current userpool user', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + auth['credentials_source'] = 'aws'; + + const spyon = jest + .spyOn(Auth.prototype, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(null); + }); + }); + + const spyon2 = jest + .spyOn(Credentials, 'getCredSource') + .mockImplementationOnce(() => { + return 'aws'; + }); + + expect.assertions(1); + expect(await auth.currentUserInfo()).toBeNull(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('federated user', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + auth['user'] = 'federated_user'; + + const spyon = jest + .spyOn(Credentials, 'getCredSource') + .mockImplementationOnce(() => { + return 'federated'; + }); + + expect.assertions(1); + expect(await auth.currentUserInfo()).toBe('federated_user'); + + spyon.mockClear(); + }); + }); + + describe('updateUserAttributes test', () => { + test('happy case', async () => { + const auth = new Auth(authOptions); + + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const attributes = { + email: 'email', + phone_number: 'phone_number', + sub: 'sub', + }; + + const spyon = jest + .spyOn(Auth.prototype, 'userSession') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(session); + }); + }); + + expect.assertions(1); + expect(await auth.updateUserAttributes(user, attributes)).toBe('SUCCESS'); + + spyon.mockClear(); + }); + }); + + describe('federatedSignIn test', () => { + test('No Identity Pool and No User Pool', async () => { + const options: AuthOptions = {}; + + const auth = new Auth(options); + + let error; + try { + await auth.federatedSignIn( + 'google', + { token: 'token', expires_at: 1234 }, + { name: 'username' } + ); + } catch (e) { + error = e; + } + + expect(error).toEqual( + new Error( + 'Federation requires either a User Pool or Identity Pool in config' + ) + ); + }); + + test('No User Pool', async () => { + const options: AuthOptions = {}; + + const auth = new Auth(options); + + let error; + try { + await auth.federatedSignIn(); + } catch (e) { + error = e; + } + + expect(error).toEqual( + new Error( + 'Federation requires either a User Pool or Identity Pool in config' + ) + ); + }); + + test('Identity Pool Missing Tokens', async () => { + const options: AuthOptions = { + region: 'region', + identityPoolId: 'awsCognitoIdentityPoolId', + }; + + const auth = new Auth(options); + + let error; + try { + await auth.federatedSignIn(); + } catch (e) { + error = e; + } + + expect(error).toEqual( + new Error( + 'Federation with Identity Pools requires tokens passed as arguments' + ) + ); + }); + + test('Identity Pools Only', async () => { + const options: AuthOptions = { + region: 'region', + identityPoolId: 'awsCognitoIdentityPoolId', + }; + + const auth = new Auth(options); + let user = null; + const spyon = jest + .spyOn(Credentials, 'set') + .mockImplementationOnce(() => { + user = { name: 'username', email: 'xxx@email.com' }; + return Promise.resolve('cred'); + }); + const spyon2 = jest + .spyOn(Auth.prototype, 'currentAuthenticatedUser') + .mockImplementation(() => { + if (!user) return Promise.reject('error'); + else return Promise.resolve(user); + }); + + await auth.federatedSignIn( + 'google', + { token: 'token', expires_at: 1234 }, + { name: 'username' } + ); + + expect(spyon).toBeCalled(); + expect(spyon2).toBeCalled(); + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('User Pools Only', async () => { + const urlOpener = jest.fn(); + + const options: AuthOptions = { + region: 'region', + userPoolId: 'userPoolId', + oauth: { + domain: 'mydomain.auth.us-east-1.amazoncognito.com', + scope: ['aws.cognito.signin.user.admin'], + redirectSignIn: 'http://localhost:3000/', + redirectSignOut: 'http://localhost:3000/', + responseType: 'code', + urlOpener, + }, + }; + + const auth = new Auth(options); + + const spyon3 = jest.spyOn(OAuth.prototype, 'oauthSignIn'); + + await auth.federatedSignIn(); + + expect(spyon3).toBeCalled(); + spyon3.mockClear(); + expect(urlOpener).toBeCalled(); + }); + + test('User Pools and Identity Pools', async () => { + const urlOpener = jest.fn(); + + const options: AuthOptions = { + region: 'region', + identityPoolId: 'awsCognitoIdentityPoolId', + userPoolId: 'userPoolId', + oauth: { + domain: 'mydomain.auth.us-east-1.amazoncognito.com', + scope: ['aws.cognito.signin.user.admin'], + redirectSignIn: 'http://localhost:3000/', + redirectSignOut: 'http://localhost:3000/', + responseType: 'code', + urlOpener, + }, + }; + + const auth = new Auth(options); + + const spyon3 = jest.spyOn(OAuth.prototype, 'oauthSignIn'); + + let user = null; + const spyon = jest + .spyOn(Credentials, 'set') + .mockImplementationOnce(() => { + user = { name: 'username', email: 'xxx@email.com' }; + return Promise.resolve('cred'); + }); + const spyon2 = jest + .spyOn(Auth.prototype, 'currentAuthenticatedUser') + .mockImplementation(() => { + if (!user) return Promise.reject('error'); + else return Promise.resolve(user); + }); + + await auth.federatedSignIn( + 'google', + { token: 'token', expires_at: 1234 }, + { name: 'username' } + ); + + expect(spyon).toBeCalled(); + expect(spyon2).toBeCalled(); + spyon.mockClear(); + spyon2.mockClear(); + + expect(spyon3).not.toBeCalled(); + spyon3.mockClear(); + expect(urlOpener).not.toBeCalled(); + }); + }); + + describe('handleAuthResponse test', () => { + beforeAll(() => { + jest + .spyOn(Auth.prototype, 'currentAuthenticatedUser') + .mockImplementation(() => { + throw new Error('no user logged in'); + }); + }); + + test('User Pools Code Flow', async () => { + const options: AuthOptions = { + region: 'region', + userPoolId: 'userPoolId', + oauth: { + domain: 'mydomain.auth.us-east-1.amazoncognito.com', + scope: ['aws.cognito.signin.user.admin'], + redirectSignIn: 'http://localhost:3000/', + redirectSignOut: 'http://localhost:3000/', + responseType: 'code', + }, + }; + + const auth = new Auth(options); + + const handleAuthResponseSpy = jest + .spyOn(OAuth.prototype, 'handleAuthResponse') + .mockReturnValueOnce({ idToken: '' }); + jest + .spyOn(CognitoUserSession.prototype, 'getIdToken') + .mockReturnValueOnce({ decodePayload: () => ({}) }); + jest.spyOn(Credentials, 'set').mockImplementationOnce(c => c); + (auth as any).createCognitoUser = jest.fn(() => ({ + getUsername: jest.fn(), + setSignInUserSession: jest.fn(), + })); + const replaceStateSpy = jest + .spyOn(window.history, 'replaceState') + .mockReturnThis(); + + const code = 'XXXX-YYY-ZZZ'; + const state = 'STATEABC'; + const url = `${ + (options.oauth as AwsCognitoOAuthOpts).redirectSignIn + }?code=${code}&state=${state}`; + + (oauthStorage.getState as jest.Mock).mockReturnValueOnce(state); + await (auth as any)._handleAuthResponse(url); + + expect(handleAuthResponseSpy).toHaveBeenCalledWith(url); + expect(replaceStateSpy).toHaveBeenCalledWith( + {}, + null, + (options.oauth as AwsCognitoOAuthOpts).redirectSignIn + ); + }); + + test('User Pools Implicit Flow', async () => { + const options: AuthOptions = { + region: 'region', + userPoolId: 'userPoolId', + oauth: { + domain: 'mydomain.auth.us-east-1.amazoncognito.com', + scope: ['aws.cognito.signin.user.admin'], + redirectSignIn: 'http://localhost:3000/', + redirectSignOut: 'http://localhost:3000/', + responseType: 'token', + }, + }; + + const auth = new Auth(options); + + const handleAuthResponseSpy = jest + .spyOn(OAuth.prototype, 'handleAuthResponse') + .mockReturnValueOnce({ idToken: '' }); + jest + .spyOn(CognitoUserSession.prototype, 'getIdToken') + .mockReturnValueOnce({ decodePayload: () => ({}) }); + jest.spyOn(Credentials, 'set').mockImplementationOnce(c => c); + (auth as any).createCognitoUser = jest.fn(() => ({ + getUsername: jest.fn(), + setSignInUserSession: jest.fn(), + })); + const replaceStateSpy = jest + .spyOn(window.history, 'replaceState') + .mockReturnThis(); + + const token = 'XXXX.YYY.ZZZ'; + const state = 'STATEABC'; + const url = `${ + (options.oauth as AwsCognitoOAuthOpts).redirectSignIn + }#access_token=${token}&state=${state}`; + + await (auth as any)._handleAuthResponse(url); + + expect(handleAuthResponseSpy).toHaveBeenCalledWith(url); + expect(replaceStateSpy).toHaveBeenCalledWith( + {}, + null, + (options.oauth as AwsCognitoOAuthOpts).redirectSignIn + ); + }); + + test('No User Pools', async () => { + const urlOpener = jest.fn(); + + const options: AuthOptions = {}; + + const auth = new Auth(options); + + let error; + try { + await (auth as any)._handleAuthResponse(' '); + } catch (e) { + error = e; + } + + expect(error).toEqual( + new Error('OAuth responses require a User Pool defined in config') + ); + }); + + test('User Pools and Identity Pools', async () => { + const options: AuthOptions = { + region: 'region', + userPoolId: 'userPoolId', + oauth: { + domain: 'mydomain.auth.us-east-1.amazoncognito.com', + scope: ['aws.cognito.signin.user.admin'], + redirectSignIn: 'http://localhost:3000/', + redirectSignOut: 'http://localhost:3000/', + responseType: 'code', + }, + identityPoolId: 'awsCognitoIdentityPoolId', + }; + + const auth = new Auth(options); + + const handleAuthResponseSpy = jest + .spyOn(OAuth.prototype, 'handleAuthResponse') + .mockReturnValueOnce({ idToken: '' }); + jest + .spyOn(CognitoUserSession.prototype, 'getIdToken') + .mockReturnValueOnce({ decodePayload: () => ({}) }); + jest.spyOn(Credentials, 'set').mockImplementationOnce(c => c); + (auth as any).createCognitoUser = jest.fn(() => ({ + getUsername: jest.fn(), + setSignInUserSession: jest.fn(), + })); + const replaceStateSpy = jest + .spyOn(window.history, 'replaceState') + .mockReturnThis(); + + const code = 'XXXX-YYY-ZZZ'; + const url = `${ + (options.oauth as AwsCognitoOAuthOpts).redirectSignIn + }?code=${code}`; + await (auth as any)._handleAuthResponse(url); + + expect(handleAuthResponseSpy).toHaveBeenCalledWith(url); + expect(replaceStateSpy).toHaveBeenCalledWith( + {}, + null, + (options.oauth as AwsCognitoOAuthOpts).redirectSignIn + ); + }); + }); + + describe('verifiedContact test', () => { + test('happy case with unverified', async () => { + const spyon = jest + .spyOn(Auth.prototype, 'userAttributes') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res([ + { + Name: 'email', + Value: 'email@amazon.com', + }, + { + Name: 'phone_number', + Value: '+12345678901', + }, + ]); + }); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect(await auth.verifiedContact(user)).toEqual({ + unverified: { email: 'email@amazon.com', phone_number: '+12345678901' }, + verified: {}, + }); + + spyon.mockClear(); + }); + + test('happy case with unverified', async () => { + const spyon = jest + .spyOn(Auth.prototype, 'userAttributes') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res([ + { + Name: 'email', + Value: 'email@amazon.com', + }, + { + Name: 'phone_number', + Value: '+12345678901', + }, + { + Name: 'email_verified', + Value: true, + }, + { + Name: 'phone_number_verified', + Value: true, + }, + ]); + }); + }); + + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + expect(await auth.verifiedContact(user)).toEqual({ + unverified: {}, + verified: { email: 'email@amazon.com', phone_number: '+12345678901' }, + }); + + spyon.mockClear(); + }); + }); + + describe('currentUserPoolUser test', () => { + test('happy case', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(CognitoUserPool.prototype, 'getCurrentUser') + .mockImplementation(() => { + return user; + }); + const spyon2 = jest + .spyOn(CognitoUser.prototype, 'getSession') + .mockImplementation(callback => { + return callback(null, session); + }); + + const spyon3 = jest + .spyOn(CognitoUser.prototype, 'getUserData') + .mockImplementationOnce(callback => { + const data = { + PreferredMfaSetting: 'SMS', + UserAttributes: [{ Name: 'address', Value: 'xxxx' }], + }; + callback(null, data); + }); + + const spyon4 = jest + .spyOn(CognitoUserSession.prototype, 'getAccessToken') + .mockImplementationOnce(() => { + return new CognitoAccessToken({ AccessToken: 'accessToken' }); + }); + + const spyon5 = jest + .spyOn(CognitoAccessToken.prototype, 'decodePayload') + .mockImplementation(() => { + return { scope: USER_ADMIN_SCOPE }; + }); + + expect.assertions(1); + expect(await auth.currentUserPoolUser()).toBe( + Object.assign(user, { + attributes: { + address: 'xxxx', + }, + preferredMFA: 'SMS', + }) + ); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + spyon4.mockClear(); + spyon5.mockClear(); + }); + + test('no current user', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(CognitoUserPool.prototype, 'getCurrentUser') + .mockImplementation(() => { + return null; + }); + + expect.assertions(1); + try { + await auth.currentUserPoolUser(); + } catch (e) { + expect(e).toBe('No current user'); + } + + spyon.mockClear(); + }); + + test('No userPool in config', async () => { + const auth = new Auth(authOptionsWithNoUserPoolId); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + const errorMessage = new NoUserPoolError(AuthErrorTypes.EmptyCode); + + expect.assertions(2); + expect(auth.currentUserPoolUser().then()).rejects.toThrow( + NoUserPoolError + ); + expect(auth.currentUserPoolUser().then()).rejects.toEqual(errorMessage); + }); + + test('get session error', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(CognitoUserPool.prototype, 'getCurrentUser') + .mockImplementation(() => { + return user; + }); + const spyon2 = jest + .spyOn(CognitoUser.prototype, 'getSession') + .mockImplementation(callback => { + return callback('err', null); + }); + + const spyon3 = jest.spyOn(CognitoUser.prototype, 'getUserData'); + + expect.assertions(2); + try { + await auth.currentUserPoolUser(); + } catch (e) { + expect(e).toBe('err'); + expect(spyon3).not.toBeCalled(); + } + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + }); + + test('get user data error because of user is deleted or disabled', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(CognitoUserPool.prototype, 'getCurrentUser') + .mockImplementation(() => { + return user; + }); + const spyon2 = jest + .spyOn(CognitoUser.prototype, 'getSession') + .mockImplementation(callback => { + return callback(null, session); + }); + const spyon3 = jest + .spyOn(CognitoUser.prototype, 'getUserData') + .mockImplementationOnce(callback => { + callback( + { + message: 'User is disabled', + }, + null + ); + }); + + const spyon4 = jest + .spyOn(CognitoUserSession.prototype, 'getAccessToken') + .mockImplementationOnce(() => { + return new CognitoAccessToken({ AccessToken: 'accessToken' }); + }); + + const spyon5 = jest + .spyOn(CognitoAccessToken.prototype, 'decodePayload') + .mockImplementation(() => { + return { scope: USER_ADMIN_SCOPE }; + }); + + expect.assertions(1); + try { + await auth.currentUserPoolUser(); + } catch (e) { + expect(e).toEqual({ + message: 'User is disabled', + }); + } + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + spyon4.mockClear(); + spyon5.mockClear(); + }); + + test('bypass the error if the user is not deleted or disabled', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(CognitoUserPool.prototype, 'getCurrentUser') + .mockImplementation(() => { + return user; + }); + const spyon2 = jest + .spyOn(CognitoUser.prototype, 'getSession') + .mockImplementation(callback => { + return callback(null, session); + }); + const spyon3 = jest + .spyOn(CognitoUser.prototype, 'getUserData') + .mockImplementationOnce(callback => { + callback( + { + message: 'other error', + }, + null + ); + }); + + const spyon4 = jest + .spyOn(CognitoUserSession.prototype, 'getAccessToken') + .mockImplementationOnce(() => { + return new CognitoAccessToken({ AccessToken: 'accessToken' }); + }); + + const spyon5 = jest + .spyOn(CognitoAccessToken.prototype, 'decodePayload') + .mockImplementation(() => { + return { scope: USER_ADMIN_SCOPE }; + }); + + expect.assertions(1); + + expect(await auth.currentUserPoolUser()).toEqual(user); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + spyon4.mockClear(); + spyon5.mockClear(); + }); + + test('directly return the user if no permission(scope) to get the user data', async () => { + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + + const spyon = jest + .spyOn(CognitoUserPool.prototype, 'getCurrentUser') + .mockImplementation(() => { + return user; + }); + const spyon2 = jest + .spyOn(CognitoUser.prototype, 'getSession') + .mockImplementation(callback => { + return callback(null, session); + }); + + const spyon3 = jest + .spyOn(CognitoUser.prototype, 'getUserData') + .mockImplementationOnce(callback => { + const data = { + PreferredMfaSetting: 'SMS', + UserAttributes: [{ Name: 'address', Value: 'xxxx' }], + }; + callback(null, data); + }); + + const spyon4 = jest + .spyOn(CognitoUserSession.prototype, 'getAccessToken') + .mockImplementationOnce(() => { + return new CognitoAccessToken({ AccessToken: 'accessToken' }); + }); + + const spyon5 = jest + .spyOn(CognitoAccessToken.prototype, 'decodePayload') + .mockImplementation(() => { + return { scope: '' }; + }); + + expect.assertions(2); + expect(spyon3).not.toBeCalled(); + expect(await auth.currentUserPoolUser()).toBe(user); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + spyon4.mockClear(); + spyon5.mockClear(); + }); + }); + + describe('sendCustomChallengeAnswer', () => { + test('happy case', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'sendCustomChallengeAnswer') + .mockImplementationOnce((challengeResponses, callback) => { + callback.onSuccess(session); + }); + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + const userAfterCustomChallengeAnswer = Object.assign( + new CognitoUser({ + Username: 'username', + Pool: userPool, + }), + { + challengeName: 'CUSTOM_CHALLENGE', + challengeParam: 'challengeParam', + } + ); + + const spyon2 = jest + .spyOn(auth, 'currentUserPoolUser') + .mockImplementationOnce(() => { + return Promise.resolve(user); + }); + + expect.assertions(1); + expect( + await auth.sendCustomChallengeAnswer( + userAfterCustomChallengeAnswer, + 'challengeResponse' + ) + ).toEqual(user); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('customChallenge', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'sendCustomChallengeAnswer') + .mockImplementationOnce((challengeResponses, callback) => { + callback.customChallenge('challengeParam'); + }); + const auth = new Auth(authOptions); + const user = new CognitoUser({ + Username: 'username', + Pool: userPool, + }); + const userAfterCustomChallengeAnswer = Object.assign( + new CognitoUser({ + Username: 'username', + Pool: userPool, + }), + { + challengeName: 'CUSTOM_CHALLENGE', + challengeParam: 'challengeParam', + } + ); + + expect.assertions(1); + expect( + await auth.sendCustomChallengeAnswer( + userAfterCustomChallengeAnswer, + 'challengeResponse' + ) + ).toEqual(userAfterCustomChallengeAnswer); + + spyon.mockClear(); + }); + + test('onFailure', async () => { + const spyon = jest + .spyOn(CognitoUser.prototype, 'sendCustomChallengeAnswer') + .mockImplementationOnce((challengeResponses, callback) => { + callback.onFailure('err'); + }); + + const auth = new Auth(authOptions); + const userAfterCustomChallengeAnswer = Object.assign( + new CognitoUser({ + Username: 'username', + Pool: userPool, + }), + { + challengeName: 'CUSTOM_CHALLENGE', + challengeParam: 'challengeParam', + } + ); + + expect.assertions(1); + try { + await auth.sendCustomChallengeAnswer( + userAfterCustomChallengeAnswer, + 'challengeResponse' + ); + } catch (e) { + expect(e).toBe('err'); + } + + spyon.mockClear(); + }); + + test('no userPool', async () => { + const spyon = jest.spyOn( + CognitoUser.prototype, + 'sendCustomChallengeAnswer' + ); + + const auth = new Auth(authOptionsWithNoUserPoolId); + const userAfterCustomChallengeAnswer = Object.assign( + new CognitoUser({ + Username: 'username', + Pool: userPool, + }), + { + challengeName: 'CUSTOM_CHALLENGE', + challengeParam: 'challengeParam', + } + ); + const errorMessage = new NoUserPoolError( + AuthErrorTypes.MissingAuthConfig + ); + + expect.assertions(2); + expect( + auth + .sendCustomChallengeAnswer( + userAfterCustomChallengeAnswer, + 'challengeResponse' + ) + .then() + ).rejects.toThrow(AuthError); + + expect( + auth + .sendCustomChallengeAnswer( + userAfterCustomChallengeAnswer, + 'challengeResponse' + ) + .then() + ).rejects.toEqual(errorMessage); + + spyon.mockClear(); + }); + }); }); - - - - diff --git a/packages/auth/src/Auth.ts b/packages/auth/src/Auth.ts index 96d23d43109..45f42530410 100644 --- a/packages/auth/src/Auth.ts +++ b/packages/auth/src/Auth.ts @@ -12,53 +12,53 @@ */ import { - AuthOptions, - FederatedResponse, - SignUpParams, - FederatedUser, - ConfirmSignUpOptions, - SignOutOpts, - CurrentUserOpts, - GetPreferredMFAOpts, - SignInOpts, - isUsernamePasswordOpts, - isCognitoHostedOpts, - isFederatedSignInOptions, - isFederatedSignInOptionsCustom, - FederatedSignInOptionsCustom, - LegacyProvider, - FederatedSignInOptions, - AwsCognitoOAuthOpts + AuthOptions, + FederatedResponse, + SignUpParams, + FederatedUser, + ConfirmSignUpOptions, + SignOutOpts, + CurrentUserOpts, + GetPreferredMFAOpts, + SignInOpts, + isUsernamePasswordOpts, + isCognitoHostedOpts, + isFederatedSignInOptions, + isFederatedSignInOptionsCustom, + FederatedSignInOptionsCustom, + LegacyProvider, + FederatedSignInOptions, + AwsCognitoOAuthOpts, } from './types'; import { - AWS, - ConsoleLogger as Logger, - Constants, - Hub, - JS, - Parser, - Credentials, - StorageHelper, - ICredentials, - Platform + AWS, + ConsoleLogger as Logger, + Constants, + Hub, + JS, + Parser, + Credentials, + StorageHelper, + ICredentials, + Platform, } from '@aws-amplify/core'; import { - CookieStorage, - CognitoUserPool, - AuthenticationDetails, - ICognitoUserPoolData, - ICognitoUserData, - ISignUpResult, - CognitoUser, - MFAOption, - CognitoUserSession, - IAuthenticationCallback, - ICognitoUserAttributeData, - CognitoUserAttribute, - CognitoIdToken, - CognitoRefreshToken, - CognitoAccessToken + CookieStorage, + CognitoUserPool, + AuthenticationDetails, + ICognitoUserPoolData, + ICognitoUserData, + ISignUpResult, + CognitoUser, + MFAOption, + CognitoUserSession, + IAuthenticationCallback, + ICognitoUserAttributeData, + CognitoUserAttribute, + CognitoIdToken, + CognitoRefreshToken, + CognitoAccessToken, } from 'amazon-cognito-identity-js'; import { parse } from 'url'; @@ -70,1647 +70,1821 @@ import { AuthErrorTypes } from './types/Auth'; const logger = new Logger('AuthClass'); const USER_ADMIN_SCOPE = 'aws.cognito.signin.user.admin'; -const AMPLIFY_SYMBOL = ((typeof Symbol !== 'undefined' && typeof Symbol.for === 'function') ? - Symbol.for('amplify_default') : '@@amplify_default') as Symbol; +const AMPLIFY_SYMBOL = (typeof Symbol !== 'undefined' && +typeof Symbol.for === 'function' + ? Symbol.for('amplify_default') + : '@@amplify_default') as Symbol; -const dispatchAuthEvent = (event:string, data:any, message:string) => { - Hub.dispatch('auth', { event, data, message }, 'Auth', AMPLIFY_SYMBOL); +const dispatchAuthEvent = (event: string, data: any, message: string) => { + Hub.dispatch('auth', { event, data, message }, 'Auth', AMPLIFY_SYMBOL); }; export enum CognitoHostedUIIdentityProvider { - Cognito = 'COGNITO', - Google = 'Google', - Facebook = 'Facebook', - Amazon = 'LoginWithAmazon', + Cognito = 'COGNITO', + Google = 'Google', + Facebook = 'Facebook', + Amazon = 'LoginWithAmazon', } /** -* Provide authentication steps -*/ + * Provide authentication steps + */ export default class AuthClass { - private _config: AuthOptions; - private userPool = null; - private user: any = null; - private _oAuthHandler: OAuth; - private _storage; - private _storageSync; - - /** - * Initialize Auth with AWS configurations - * @param {Object} config - Configuration of the Auth - */ - constructor(config: AuthOptions) { - this.configure(config); - - this.currentUserCredentials = this.currentUserCredentials.bind(this); - - if (AWS.config) { - AWS.config.update({ customUserAgent: Constants.userAgent }); - } else { - logger.warn('No AWS.config'); - } - - Hub.listen('auth', ({ payload }) => { - const { event } = payload; - switch (event) { - case 'signIn': - this._storage.setItem('amplify-signin-with-hostedUI', 'false'); - break; - case 'signOut': - this._storage.removeItem('amplify-signin-with-hostedUI'); - break; - case 'cognitoHostedUI': - this._storage.setItem('amplify-signin-with-hostedUI', 'true'); - break; - } - }); - } - - public getModuleName() { - return 'Auth'; - } - - configure(config) { - if (!config) return this._config || {}; - logger.debug('configure Auth'); - const conf = Object.assign({}, this._config, Parser.parseMobilehubConfig(config).Auth, config); - this._config = conf; - const { - userPoolId, - userPoolWebClientId, - cookieStorage, - oauth, - region, - identityPoolId, - mandatorySignIn, - refreshHandlers, - identityPoolRegion - } = this._config; - - if (!this._config.storage) { - // backward compatbility - if (cookieStorage) this._storage = new CookieStorage(cookieStorage); - else { - this._storage = new StorageHelper().getStorage(); - } - } else { - if (!this._isValidAuthStorage(this._config.storage)) { - logger.error('The storage in the Auth config is not valid!'); - throw new Error('Empty storage object'); - } - this._storage = this._config.storage; - } - - this._storageSync = Promise.resolve(); - if (typeof this._storage['sync'] === 'function') { - this._storageSync = this._storage['sync'](); - } - - if (userPoolId) { - const userPoolData: ICognitoUserPoolData = { - UserPoolId: userPoolId, - ClientId: userPoolWebClientId, - }; - userPoolData.Storage = this._storage; - - this.userPool = new CognitoUserPool(userPoolData); - } - - Credentials.configure({ - mandatorySignIn, - region: identityPoolRegion || region, - userPoolId, - identityPoolId, - refreshHandlers, - storage: this._storage - }); - - // initiailize cognitoauth client if hosted ui options provided - // to keep backward compatibility: - const cognitoHostedUIConfig = oauth? (isCognitoHostedOpts(this._config.oauth) - ? oauth : (oauth).awsCognito) - : undefined; - - if (cognitoHostedUIConfig) { - const cognitoAuthParams = Object.assign( - { - cognitoClientId: userPoolWebClientId, - UserPoolId: userPoolId, - domain: cognitoHostedUIConfig['domain'], - scopes: cognitoHostedUIConfig['scope'], - redirectSignIn: cognitoHostedUIConfig['redirectSignIn'], - redirectSignOut: cognitoHostedUIConfig['redirectSignOut'], - responseType: cognitoHostedUIConfig['responseType'], - Storage: this._storage, - urlOpener: cognitoHostedUIConfig['urlOpener'] - }, - cognitoHostedUIConfig['options'] - ); - - this._oAuthHandler = new OAuth({ - scopes: cognitoAuthParams.scopes, - config: cognitoAuthParams, - cognitoClientId: cognitoAuthParams.cognitoClientId - }); - - // **NOTE** - Remove this in a future major release as it is a breaking change - urlListener(({ url }) => { - this._handleAuthResponse(url); - }); - } - - dispatchAuthEvent( - 'configured', - null, - `The Auth category has been configured successfully` - ); - return this._config; - } - - /** - * Sign up with username, password and other attrbutes like phone, email - * @param {String | object} params - The user attirbutes used for signin - * @param {String[]} restOfAttrs - for the backward compatability - * @return - A promise resolves callback data if success - */ - public signUp(params: string | SignUpParams, ...restOfAttrs: string[]): Promise { - if (!this.userPool) { return this.rejectNoUserPool(); } - - let username: string = null; - let password: string = null; - const attributes: object[] = []; - let validationData: object[] = null; - - if (params && typeof params === 'string') { - username = params; - password = restOfAttrs ? restOfAttrs[0] : null; - const email: string = restOfAttrs ? restOfAttrs[1] : null; - const phone_number: string = restOfAttrs ? restOfAttrs[2] : null; - if (email) attributes.push({ Name: 'email', Value: email }); - if (phone_number) attributes.push({ Name: 'phone_number', Value: phone_number }); - } else if (params && typeof params === 'object') { - username = params['username']; - password = params['password']; - const attrs = params['attributes']; - if (attrs) { - Object.keys(attrs).map(key => { - const ele: object = { Name: key, Value: attrs[key] }; - attributes.push(ele); - }); - } - validationData = params['validationData'] || null; - } else { - return this.rejectAuthError(AuthErrorTypes.SignUpError); - } - - if (!username) { return this.rejectAuthError(AuthErrorTypes.EmptyUsername); } - if (!password) { return this.rejectAuthError(AuthErrorTypes.EmptyPassword); } - - logger.debug('signUp attrs:', attributes); - logger.debug('signUp validation data:', validationData); - - - return new Promise((resolve, reject) => { - this.userPool.signUp(username, password, attributes, validationData, (err, data) => { - if (err) { - dispatchAuthEvent( - 'signUp_failure', - err, - `${username} failed to signup` - ); - reject(err); - } else { - dispatchAuthEvent( - 'signUp', - data, - `${username} has signed up successfully` - ); - resolve(data); - } - }); - }); - } - - /** - * Send the verfication code to confirm sign up - * @param {String} username - The username to be confirmed - * @param {String} code - The verification code - * @param {ConfirmSignUpOptions} options - other options for confirm signup - * @return - A promise resolves callback data if success - */ - public confirmSignUp(username: string, code: string, options?: ConfirmSignUpOptions): Promise { - if (!this.userPool) { return this.rejectNoUserPool(); } - if (!username) { return this.rejectAuthError(AuthErrorTypes.EmptyUsername); } - if (!code) { return this.rejectAuthError(AuthErrorTypes.EmptyCode); } - - const user = this.createCognitoUser(username); - const forceAliasCreation = options && typeof options.forceAliasCreation === 'boolean' - ? options.forceAliasCreation : true; - - return new Promise((resolve, reject) => { - user.confirmRegistration(code, forceAliasCreation, (err, data) => { - if (err) { reject(err); } else { resolve(data); } - }); - }); - } - - /** - * Resend the verification code - * @param {String} username - The username to be confirmed - * @return - A promise resolves data if success - */ - public resendSignUp(username: string): Promise { - if (!this.userPool) { return this.rejectNoUserPool(); } - if (!username) { return this.rejectAuthError(AuthErrorTypes.EmptyUsername); } - - const user = this.createCognitoUser(username); - return new Promise((resolve, reject) => { - user.resendConfirmationCode((err, data) => { - if (err) { reject(err); } else { resolve(data); } - }); - }); - } - - /** - * Sign in - * @param {String | SignInOpts} usernameOrSignInOpts - The username to be signed in or the sign in options - * @param {String} password - The password of the username - * @return - A promise resolves the CognitoUser - */ - public signIn(usernameOrSignInOpts: string | SignInOpts, pw?: string): Promise { - if (!this.userPool) { return this.rejectNoUserPool(); } - let username = null; - let password = null; - let validationData = {}; - // for backward compatibility - if (typeof usernameOrSignInOpts === 'string') { - username = usernameOrSignInOpts; - password = pw; - } else if (isUsernamePasswordOpts(usernameOrSignInOpts)) { - if (typeof pw !== 'undefined') { - logger.warn('The password should be defined under the first parameter object!'); - } - username = usernameOrSignInOpts.username; - password = usernameOrSignInOpts.password; - validationData = usernameOrSignInOpts.validationData; - } else { - return this.rejectAuthError(AuthErrorTypes.InvalidUsername); - } - if (!username) { return this.rejectAuthError(AuthErrorTypes.EmptyUsername); } - const authDetails = new AuthenticationDetails({ - Username: username, - Password: password, - ValidationData: validationData - }); - if (password) { - return this.signInWithPassword(authDetails); - } else { - return this.signInWithoutPassword(authDetails); - } - } - - /** - * Return an object with the authentication callbacks - * @param {CognitoUser} user - the cognito user object - * @param {} resolve - function called when resolving the current step - * @param {} reject - function called when rejecting the current step - * @return - an object with the callback methods for user authentication - */ - private authCallbacks( - user: CognitoUser, - resolve: (value?: CognitoUser | any) => void, reject: (value?: any) => void - ): IAuthenticationCallback { - const that = this; - return { - onSuccess: async (session) => { - logger.debug(session); - delete (user['challengeName']); - delete (user['challengeParam']); - try { - await Credentials.clear(); - const cred = await Credentials.set(session, 'session'); - logger.debug('succeed to get cognito credentials', cred); - } catch (e) { - logger.debug('cannot get cognito credentials', e); - } finally { - try { - // In order to get user attributes and MFA methods - // We need to trigger currentUserPoolUser again - const currentUser = await this.currentUserPoolUser(); - that.user = currentUser; - dispatchAuthEvent( - 'signIn', - currentUser, - `A user ${user.getUsername()} has been signed in` - ); - resolve(currentUser); - } catch (e) { - logger.error('Failed to get the signed in user', e); - reject(e); - } - } - }, - onFailure: (err) => { - logger.debug('signIn failure', err); - dispatchAuthEvent( - 'signIn_failure', - err, - `${user.getUsername()} failed to signin` - ); - reject(err); - }, - customChallenge: (challengeParam) => { - logger.debug('signIn custom challenge answer required'); - user['challengeName'] = 'CUSTOM_CHALLENGE'; - user['challengeParam'] = challengeParam; - resolve(user); - }, - mfaRequired: (challengeName, challengeParam) => { - logger.debug('signIn MFA required'); - user['challengeName'] = challengeName; - user['challengeParam'] = challengeParam; - resolve(user); - }, - mfaSetup: (challengeName, challengeParam) => { - logger.debug('signIn mfa setup', challengeName); - user['challengeName'] = challengeName; - user['challengeParam'] = challengeParam; - resolve(user); - }, - newPasswordRequired: (userAttributes, requiredAttributes) => { - logger.debug('signIn new password'); - user['challengeName'] = 'NEW_PASSWORD_REQUIRED'; - user['challengeParam'] = { - userAttributes, - requiredAttributes - }; - resolve(user); - }, - totpRequired: (challengeName, challengeParam) => { - logger.debug('signIn totpRequired'); - user['challengeName'] = challengeName; - user['challengeParam'] = challengeParam; - resolve(user); - }, - selectMFAType: (challengeName, challengeParam) => { - logger.debug('signIn selectMFAType', challengeName); - user['challengeName'] = challengeName; - user['challengeParam'] = challengeParam; - resolve(user); - } - }; - } - - /** - * Sign in with a password - * @private - * @param {AuthenticationDetails} authDetails - the user sign in data - * @return - A promise resolves the CognitoUser object if success or mfa required - */ - private signInWithPassword(authDetails: AuthenticationDetails): Promise { - const user = this.createCognitoUser(authDetails.getUsername()); - - return new Promise((resolve, reject) => { - user.authenticateUser(authDetails, this.authCallbacks(user, resolve, reject)); - }); - } - - /** - * Sign in without a password - * @private - * @param {AuthenticationDetails} authDetails - the user sign in data - * @return - A promise resolves the CognitoUser object if success or mfa required - */ - private signInWithoutPassword(authDetails: AuthenticationDetails): Promise { - const user = this.createCognitoUser(authDetails.getUsername()); - user.setAuthenticationFlowType('CUSTOM_AUTH'); - - return new Promise((resolve, reject) => { - user.initiateAuth(authDetails, this.authCallbacks(user, resolve, reject)); - }); - } - - /** - * get user current preferred mfa option - * this method doesn't work with totp, we need to deprecate it. - * @deprecated - * @param {CognitoUser} user - the current user - * @return - A promise resolves the current preferred mfa option if success - */ - public getMFAOptions(user: CognitoUser | any): Promise { - return new Promise((res, rej) => { - user.getMFAOptions((err, mfaOptions) => { - if (err) { - logger.debug('get MFA Options failed', err); - rej(err); - return; - } - logger.debug('get MFA options success', mfaOptions); - res(mfaOptions); - return; - }); - }); - } - - /** - * get preferred mfa method - * @param {CognitoUser} user - the current cognito user - * @param {GetPreferredMFAOpts} params - options for getting the current user preferred MFA - */ - public getPreferredMFA(user: CognitoUser | any, params?: GetPreferredMFAOpts): Promise { - const that = this; - return new Promise((res, rej) => { - const bypassCache = params? params.bypassCache: false; - user.getUserData( - (err, data) => { - if (err) { - logger.debug('getting preferred mfa failed', err); - rej(err); - return; - } - - const mfaType = that._getMfaTypeFromUserData(data); - if (!mfaType) { - rej('invalid MFA Type'); - return; - } else { - res(mfaType); - return; - } - }, - { bypassCache } - ); - }); - } - - private _getMfaTypeFromUserData(data) { - let ret = null; - const preferredMFA = data.PreferredMfaSetting; - // if the user has used Auth.setPreferredMFA() to setup the mfa type - // then the "PreferredMfaSetting" would exist in the response - if (preferredMFA) { - ret = preferredMFA; - } else { - // if mfaList exists but empty, then its noMFA - const mfaList = data.UserMFASettingList; - if (!mfaList) { - // if SMS was enabled by using Auth.enableSMS(), - // the response would contain MFAOptions - // as for now Cognito only supports for SMS, so we will say it is 'SMS_MFA' - // if it does not exist, then it should be NOMFA - const MFAOptions = data.MFAOptions; - if (MFAOptions) { - ret = 'SMS_MFA'; - } else { - ret = 'NOMFA'; - } - } else if (mfaList.length === 0) { - ret = 'NOMFA'; - } else { - logger.debug('invalid case for getPreferredMFA', data); - } - } - return ret; - } - - private _getUserData(user, params) { - return new Promise((res, rej) => { - user.getUserData( - (err, data) => { - if (err) { - logger.debug('getting user data failed', err); - rej(err); - return; - } else { - res(data); - return; - } - }, - params - ); - }); - - } - - /** - * set preferred MFA method - * @param {CognitoUser} user - the current Cognito user - * @param {string} mfaMethod - preferred mfa method - * @return - A promise resolve if success - */ - public async setPreferredMFA(user: CognitoUser | any, mfaMethod: 'TOTP' | 'SMS' | 'NOMFA'): Promise { - const userData = await this._getUserData(user, { bypassCache: true }); - let smsMfaSettings = null; - let totpMfaSettings = null; - - switch (mfaMethod) { - case 'TOTP' || 'SOFTWARE_TOKEN_MFA': - totpMfaSettings = { - PreferredMfa: true, - Enabled: true - }; - break; - case 'SMS' || 'SMS_MFA': - smsMfaSettings = { - PreferredMfa: true, - Enabled: true - }; - break; - case 'NOMFA': - const mfaList = userData['UserMFASettingList']; - const currentMFAType = await this._getMfaTypeFromUserData(userData); - if (currentMFAType === 'NOMFA') { - return Promise.resolve('No change for mfa type'); - } else if (currentMFAType === 'SMS_MFA') { - smsMfaSettings = { - PreferredMfa: false, - Enabled: false - }; - } else if (currentMFAType === 'SOFTWARE_TOKEN_MFA') { - totpMfaSettings = { - PreferredMfa: false, - Enabled: false - }; - } else { - return this.rejectAuthError(AuthErrorTypes.InvalidMFA); - } - // if there is a UserMFASettingList in the response - // we need to disable every mfa type in that list - if (mfaList && mfaList.length !== 0) { - // to disable SMS or TOTP if exists in that list - mfaList.forEach(mfaType => { - if (mfaType === 'SMS_MFA') { - smsMfaSettings = { - PreferredMfa: false, - Enabled: false - }; - } else if (mfaType === 'SOFTWARE_TOKEN_MFA') { - totpMfaSettings = { - PreferredMfa: false, - Enabled: false - }; - } - }); - } - break; - default: - logger.debug('no validmfa method provided'); - return this.rejectAuthError(AuthErrorTypes.NoMFA); - } - - const that = this; - return new Promise((res, rej) => { - user.setUserMfaPreference(smsMfaSettings, totpMfaSettings, (err, result) => { - if (err) { - logger.debug('Set user mfa preference error', err); - return rej(err); - } - logger.debug('Set user mfa success', result); - logger.debug('Caching the latest user data into local'); - // cache the latest result into user data - user.getUserData( - (err, data) => { - if (err) { - logger.debug('getting user data failed', err); - return rej(err); - } else { - return res(result); - } - }, - {bypassCache: true} - ); - }); - }); - } - - /** - * diable SMS - * @deprecated - * @param {CognitoUser} user - the current user - * @return - A promise resolves is success - */ - public disableSMS(user: CognitoUser): Promise { - return new Promise((res, rej) => { - user.disableMFA((err, data) => { - if (err) { - logger.debug('disable mfa failed', err); - rej(err); - return; - } - logger.debug('disable mfa succeed', data); - res(data); - return; - }); - }); - } - - /** - * enable SMS - * @deprecated - * @param {CognitoUser} user - the current user - * @return - A promise resolves is success - */ - public enableSMS(user: CognitoUser): Promise { - return new Promise((res, rej) => { - user.enableMFA((err, data) => { - if (err) { - logger.debug('enable mfa failed', err); - rej(err); - return; - } - logger.debug('enable mfa succeed', data); - res(data); - return; - }); - }); - } - - /** - * Setup TOTP - * @param {CognitoUser} user - the current user - * @return - A promise resolves with the secret code if success - */ - public setupTOTP(user: CognitoUser | any): Promise { - return new Promise((res, rej) => { - user.associateSoftwareToken({ - onFailure: (err) => { - logger.debug('associateSoftwareToken failed', err); - rej(err); - return; - }, - associateSecretCode: (secretCode) => { - logger.debug('associateSoftwareToken sucess', secretCode); - res(secretCode); - return; - } - }); - }); - } - - /** - * verify TOTP setup - * @param {CognitoUser} user - the current user - * @param {string} challengeAnswer - challenge answer - * @return - A promise resolves is success - */ - public verifyTotpToken(user: CognitoUser | any, challengeAnswer: string): Promise { - logger.debug('verfication totp token', user, challengeAnswer); - return new Promise((res, rej) => { - user.verifySoftwareToken(challengeAnswer, 'My TOTP device', { - onFailure: (err) => { - logger.debug('verifyTotpToken failed', err); - rej(err); - return; - }, - onSuccess: (data) => { - logger.debug('verifyTotpToken success', data); - res(data); - return; - } - }); - }); - } - - /** - * Send MFA code to confirm sign in - * @param {Object} user - The CognitoUser object - * @param {String} code - The confirmation code - */ - public confirmSignIn( - user: CognitoUser | any, - code: string, - mfaType?: 'SMS_MFA' | 'SOFTWARE_TOKEN_MFA' | null - ): Promise { - if (!code) { return this.rejectAuthError(AuthErrorTypes.EmptyCode); } - - const that = this; - return new Promise((resolve, reject) => { - user.sendMFACode( - code, { - onSuccess: async (session) => { - logger.debug(session); - try { - await Credentials.clear(); - const cred = await Credentials.set(session, 'session'); - logger.debug('succeed to get cognito credentials', cred); - } catch (e) { - logger.debug('cannot get cognito credentials', e); - } finally { - that.user = user; - - dispatchAuthEvent( - 'signIn', - user, - `${user} has signed in` - ); - resolve(user); - } - }, - onFailure: (err) => { - logger.debug('confirm signIn failure', err); - reject(err); - } - }, - mfaType); - }); - } - - public completeNewPassword( - user: CognitoUser | any, - password: string, - requiredAttributes: any - ): Promise { - if (!password) { return this.rejectAuthError(AuthErrorTypes.EmptyPassword); } - - const that = this; - return new Promise((resolve, reject) => { - user.completeNewPasswordChallenge(password, requiredAttributes, { - onSuccess: async (session) => { - logger.debug(session); - try { - await Credentials.clear(); - const cred = await Credentials.set(session, 'session'); - logger.debug('succeed to get cognito credentials', cred); - } catch (e) { - logger.debug('cannot get cognito credentials', e); - } finally { - that.user = user; - dispatchAuthEvent( - 'signIn', - user, `${user} has signed in` - ); - resolve(user); - } - }, - onFailure: (err) => { - logger.debug('completeNewPassword failure', err); - dispatchAuthEvent( - 'completeNewPassword_failure', - err, - `${this.user} failed to complete the new password flow` - ); - reject(err); - }, - mfaRequired: (challengeName, challengeParam) => { - logger.debug('signIn MFA required'); - user['challengeName'] = challengeName; - user['challengeParam'] = challengeParam; - resolve(user); - }, - mfaSetup: (challengeName, challengeParam) => { - logger.debug('signIn mfa setup', challengeName); - user['challengeName'] = challengeName; - user['challengeParam'] = challengeParam; - resolve(user); - } - }); - }); - } - - /** - * Send the answer to a custom challenge - * @param {CognitoUser} user - The CognitoUser object - * @param {String} challengeResponses - The confirmation code - */ - public sendCustomChallengeAnswer(user: CognitoUser | any, challengeResponses: string): Promise { - if (!this.userPool) { return this.rejectNoUserPool(); } - if (!challengeResponses) { return this.rejectAuthError(AuthErrorTypes.EmptyChallengeResponse); } - - const that = this; - return new Promise((resolve, reject) => { - user.sendCustomChallengeAnswer(challengeResponses, this.authCallbacks(user, resolve, reject)); - }); - } - - /** - * Update an authenticated users' attributes - * @param {CognitoUser} - The currently logged in user object - * @return {Promise} - **/ - public updateUserAttributes(user: CognitoUser | any, attributes: object): Promise { - const attributeList: ICognitoUserAttributeData[] = []; - const that = this; - return new Promise((resolve, reject) => { - that.userSession(user).then(session => { - for (const key in attributes) { - if (key !== 'sub' && - key.indexOf('_verified') < 0) { - const attr: ICognitoUserAttributeData = { - 'Name': key, - 'Value': attributes[key] - }; - attributeList.push(attr); - } - } - user.updateAttributes(attributeList, (err, result) => { - if (err) { return reject(err); } else { return resolve(result); } - }); - }); - }); - } - /** - * Return user attributes - * @param {Object} user - The CognitoUser object - * @return - A promise resolves to user attributes if success - */ - public userAttributes(user: CognitoUser | any): Promise { - return new Promise((resolve, reject) => { - this.userSession(user).then(session => { - user.getUserAttributes((err, attributes) => { - if (err) { reject(err); } else { resolve(attributes); } - }); - }); - }); - } - - public verifiedContact(user: CognitoUser | any) { - const that = this; - return this.userAttributes(user) - .then(attributes => { - const attrs = that.attributesToObject(attributes); - const unverified = {}; - const verified = {}; - if (attrs['email']) { - if (attrs['email_verified']) { - verified['email'] = attrs['email']; - } else { - unverified['email'] = attrs['email']; - } - } - if (attrs['phone_number']) { - if (attrs['phone_number_verified']) { - verified['phone_number'] = attrs['phone_number']; - } else { - unverified['phone_number'] = attrs['phone_number']; - } - } - return { - verified, - unverified - }; - }); - } - - /** - * Get current authenticated user - * @return - A promise resolves to current authenticated CognitoUser if success - */ - public currentUserPoolUser(params?: CurrentUserOpts): Promise { - if (!this.userPool) { return this.rejectNoUserPool(); } - const that = this; - return new Promise((res, rej) => { - this._storageSync.then(() => { - const user = that.userPool.getCurrentUser(); - if (!user) { - logger.debug('Failed to get user from user pool'); - rej('No current user'); - return; - } - - // refresh the session if the session expired. - user.getSession((err, session) => { - if (err) { - logger.debug('Failed to get the user session', err); - rej(err); - return; - } - - // get user data from Cognito - const bypassCache = params ? params.bypassCache : false; - // validate the token's scope fisrt before calling this function - const { scope = '' } = session.getAccessToken().decodePayload(); - if (scope.split(' ').includes(USER_ADMIN_SCOPE)) { - user.getUserData( - (err, data) => { - if (err) { - logger.debug('getting user data failed', err); - // Make sure the user is still valid - if (err.message === 'User is disabled' || err.message === 'User does not exist.') { - rej(err); - } else { - // the error may also be thrown when lack of permissions to get user info etc - // in that case we just bypass the error - res(user); - } - return; - } - const preferredMFA = data.PreferredMfaSetting || 'NOMFA'; - const attributeList = []; - - for (let i = 0; i < data.UserAttributes.length; i++) { - const attribute = { - Name: data.UserAttributes[i].Name, - Value: data.UserAttributes[i].Value, - }; - const userAttribute = new CognitoUserAttribute(attribute); - attributeList.push(userAttribute); - } - - const attributes = that.attributesToObject(attributeList); - Object.assign(user, { attributes, preferredMFA }); - return res(user); - }, - { bypassCache } - ); - } else { - logger.debug(`Unable to get the user data because the ${USER_ADMIN_SCOPE} ` + - `is not in the scopes of the access token`); - return res(user); - } - }); - }).catch(e => { - logger.debug('Failed to sync cache info into memory', e); - return rej(e); - }); - }); - } - - /** - * Get current authenticated user - * @param {CurrentUserOpts} - options for getting the current user - * @return - A promise resolves to current authenticated CognitoUser if success - */ - public async currentAuthenticatedUser(params?: CurrentUserOpts): Promise { - logger.debug('getting current authenticated user'); - let federatedUser = null; - try { - await this._storageSync; - } catch (e) { - logger.debug('Failed to sync cache info into memory', e); - throw e; - } - - try { - federatedUser = JSON.parse(this._storage.getItem('aws-amplify-federatedInfo')).user; - } catch (e) { - logger.debug('cannot load federated user from auth storage'); - } - - if (federatedUser) { - this.user = federatedUser; - logger.debug('get current authenticated federated user', this.user); - return this.user; - } else { - logger.debug('get current authenticated userpool user'); - let user = null; - try { - user = await this.currentUserPoolUser(params); - } catch (e) { - if (e === 'No userPool') { - logger.error('Cannot get the current user because the user pool is missing. ' + - 'Please make sure the Auth module is configured with a valid Cognito User Pool ID'); - } - logger.debug('The user is not authenticated by the error', e); - throw ('not authenticated'); - } - this.user = user; - return this.user; - } - } - - /** - * Get current user's session - * @return - A promise resolves to session object if success - */ - public currentSession(): Promise { - const that = this; - logger.debug('Getting current session'); - // Purposely not calling the reject method here because we don't need a console error - if (!this.userPool) { return Promise.reject(); } - - return new Promise((res, rej) => { - that.currentUserPoolUser().then(user => { - that.userSession(user).then(session => { - res(session); - return; - }).catch(e => { - logger.debug('Failed to get the current session', e); - rej(e); - return; - }); - }).catch(e => { - logger.debug('Failed to get the current user', e); - rej(e); - return; - }); - }); - } - - /** - * Get the corresponding user session - * @param {Object} user - The CognitoUser object - * @return - A promise resolves to the session - */ - public userSession(user): Promise { - if (!user) { - logger.debug('the user is null'); - return this.rejectAuthError(AuthErrorTypes.NoUserSession); - } - return new Promise((resolve, reject) => { - logger.debug('Getting the session from this user:', user); - user.getSession((err, session) => { - if (err) { - logger.debug('Failed to get the session from user', user); - reject(err); - return; - } else { - logger.debug('Succeed to get the user session', session); - resolve(session); - return; - } - }); - }); - } - - /** - * Get authenticated credentials of current user. - * @return - A promise resolves to be current user's credentials - */ - public async currentUserCredentials(): Promise { - const that = this; - logger.debug('Getting current user credentials'); - - try { - await this._storageSync; - } catch (e) { - logger.debug('Failed to sync cache info into memory', e); - throw e; - } - - // first to check whether there is federation info in the auth storage - let federatedInfo = null; - try { - federatedInfo = JSON.parse(this._storage.getItem('aws-amplify-federatedInfo')); - } catch (e) { - logger.debug('failed to get or parse item aws-amplify-federatedInfo', e); - } - - if (federatedInfo) { - // refresh the jwt token here if necessary - return Credentials.refreshFederatedToken(federatedInfo); - } else { - return this.currentSession() - .then(session => { - logger.debug('getting session success', session); - return Credentials.set(session, 'session'); - }).catch((error) => { - logger.debug('getting session failed', error); - return Credentials.set(null, 'guest'); - }); - } - } - - - public currentCredentials(): Promise { - logger.debug('getting current credntials'); - return Credentials.get(); - } - - /** - * Initiate an attribute confirmation request - * @param {Object} user - The CognitoUser - * @param {Object} attr - The attributes to be verified - * @return - A promise resolves to callback data if success - */ - public verifyUserAttribute(user: CognitoUser | any, attr: string): Promise { - return new Promise((resolve, reject) => { - user.getAttributeVerificationCode(attr, { - onSuccess() { return resolve(); }, - onFailure(err) { return reject(err); } - }); - }); - } - - /** - * Confirm an attribute using a confirmation code - * @param {Object} user - The CognitoUser - * @param {Object} attr - The attribute to be verified - * @param {String} code - The confirmation code - * @return - A promise resolves to callback data if success - */ - public verifyUserAttributeSubmit(user: CognitoUser | any, attr: string, code: string): Promise { - if (!code) { return this.rejectAuthError(AuthErrorTypes.EmptyCode); } - - return new Promise((resolve, reject) => { - user.verifyAttribute(attr, code, { - onSuccess(data) { - resolve(data); - return; - }, - onFailure(err) { - reject(err); - return; - } - }); - }); - } - - public verifyCurrentUserAttribute(attr: string): Promise { - const that = this; - return that.currentUserPoolUser() - .then(user => that.verifyUserAttribute(user, attr)); - } - - /** - * Confirm current user's attribute using a confirmation code - * @param {Object} attr - The attribute to be verified - * @param {String} code - The confirmation code - * @return - A promise resolves to callback data if success - */ - verifyCurrentUserAttributeSubmit(attr: string, code: string): Promise { - const that = this; - return that.currentUserPoolUser() - .then(user => that.verifyUserAttributeSubmit(user, attr, code)); - } - - private async cognitoIdentitySignOut(opts: SignOutOpts, user: CognitoUser | any) { - try { - await this._storageSync; - } catch (e) { - logger.debug('Failed to sync cache info into memory', e); - throw e; - } - - const isSignedInHostedUI = this._oAuthHandler - && this._storage.getItem('amplify-signin-with-hostedUI') === 'true'; - - return new Promise((res, rej) => { - if (opts && opts.global) { - logger.debug('user global sign out', user); - // in order to use global signout - // we must validate the user as an authenticated user by using getSession - user.getSession((err, result) => { - if (err) { - logger.debug('failed to get the user session', err); - return rej(err); - } - user.globalSignOut({ - onSuccess: (data) => { - logger.debug('global sign out success'); - if (isSignedInHostedUI) { - return res(this._oAuthHandler.signOut()); - } else { - return res(); - } - }, - onFailure: (err) => { - logger.debug('global sign out failed', err); - return rej(err); - } - }); - }); - } else { - logger.debug('user sign out', user); - user.signOut(); - if (isSignedInHostedUI) { - return res(this._oAuthHandler.signOut()); - } else { - return res(); - } - } - }); - } - - /** - * Sign out method - * @ - * @return - A promise resolved if success - */ - public async signOut(opts?: SignOutOpts): Promise { - try { - await this.cleanCachedItems(); - } catch (e) { - logger.debug('failed to clear cached items'); - } - - if (this.userPool) { - const user = this.userPool.getCurrentUser(); - if (user) { - await this.cognitoIdentitySignOut(opts, user); - } else { - logger.debug('no current Cognito user'); - } - } else { - logger.debug('no Congito User pool'); - } - - /** - * Note for future refactor - no reliable way to get username with - * Cognito User Pools vs Identity when federating with Social Providers - * This is why we need a well structured session object that can be inspected - * and information passed back in the message below for Hub dispatch - */ - dispatchAuthEvent( - 'signOut', - this.user, - `A user has been signed out` - ); - this.user = null; - } - - private async cleanCachedItems() { - // clear cognito cached item - await Credentials.clear(); - } - - /** - * Change a password for an authenticated user - * @param {Object} user - The CognitoUser object - * @param {String} oldPassword - the current password - * @param {String} newPassword - the requested new password - * @return - A promise resolves if success - */ - public changePassword(user: CognitoUser | any, oldPassword: string, newPassword: string): Promise<"SUCCESS"> { - return new Promise((resolve, reject) => { - this.userSession(user).then(session => { - user.changePassword(oldPassword, newPassword, (err, data) => { - if (err) { - logger.debug('change password failure', err); - return reject(err); - } else { - return resolve(data); - } - }); - }); - }); - } - - /** - * Initiate a forgot password request - * @param {String} username - the username to change password - * @return - A promise resolves if success - */ - public forgotPassword(username: string): Promise { - if (!this.userPool) { return this.rejectNoUserPool(); } - if (!username) { return this.rejectAuthError(AuthErrorTypes.EmptyUsername); } - - const user = this.createCognitoUser(username); - return new Promise((resolve, reject) => { - user.forgotPassword({ - onSuccess: () => { - resolve(); - return; - }, - onFailure: err => { - logger.debug('forgot password failure', err); - reject(err); - return; - }, - inputVerificationCode: data => { - resolve(data); - return; - } - }); - }); - } - - /** - * Confirm a new password using a confirmation Code - * @param {String} username - The username - * @param {String} code - The confirmation code - * @param {String} password - The new password - * @return - A promise that resolves if success - */ - public forgotPasswordSubmit( - username: string, - code: string, - password: string - ): Promise { - if (!this.userPool) { return this.rejectNoUserPool(); } - if (!username) { return this.rejectAuthError(AuthErrorTypes.EmptyUsername); } - if (!code) { return this.rejectAuthError(AuthErrorTypes.EmptyCode); } - if (!password) { return this.rejectAuthError(AuthErrorTypes.EmptyPassword); } - - const user = this.createCognitoUser(username); - return new Promise((resolve, reject) => { - user.confirmPassword(code, password, { - onSuccess: () => { - resolve(); - return; - }, - onFailure: err => { - reject(err); - return; - } - }); - }); - } - - /** - * Get user information - * @async - * @return {Object }- current User's information - */ - public async currentUserInfo() { - const source = Credentials.getCredSource(); - - if (!source || source === 'aws' || source === 'userPool') { - const user = await this.currentUserPoolUser() - .catch(err => logger.debug(err)); - if (!user) { return null; } - - try { - const attributes = await this.userAttributes(user); - const userAttrs: object = this.attributesToObject(attributes); - let credentials = null; - try { - credentials = await this.currentCredentials(); - } catch (e) { - logger.debug('Failed to retrieve credentials while getting current user info', e); - } - - - const info = { - 'id': credentials ? credentials.identityId : undefined, - 'username': user.getUsername(), - 'attributes': userAttrs - }; - return info; - } catch (err) { - logger.debug('currentUserInfo error', err); - return {}; - } - } - - if (source === 'federated') { - const user = this.user; - return user ? user : {}; - } - } - - - public async federatedSignIn(options?: FederatedSignInOptions): - Promise; - public async federatedSignIn( - provider: LegacyProvider, - response: FederatedResponse, - user: FederatedUser - ): Promise; - public async federatedSignIn(options?: FederatedSignInOptionsCustom): - Promise; - public async federatedSignIn( - providerOrOptions: LegacyProvider | FederatedSignInOptions | FederatedSignInOptionsCustom, - response?: FederatedResponse, - user?: FederatedUser - ): Promise { - - - if (!this._config.identityPoolId && !this._config.userPoolId) { - throw new Error(`Federation requires either a User Pool or Identity Pool in config`); - } - - // Ensure backwards compatability - if (typeof providerOrOptions === 'undefined') { - if (this._config.identityPoolId && !this._config.userPoolId) { - throw new Error(`Federation with Identity Pools requires tokens passed as arguments`); - } - } - - if (isFederatedSignInOptions(providerOrOptions) - || isFederatedSignInOptionsCustom(providerOrOptions) - || typeof providerOrOptions === 'undefined') { - - const options = providerOrOptions || { provider: CognitoHostedUIIdentityProvider.Cognito }; - const provider = isFederatedSignInOptions(options) - ? options.provider - : (options as FederatedSignInOptionsCustom).customProvider; - - const customState = isFederatedSignInOptions(options) - ? options.customState - : (options as FederatedSignInOptionsCustom).customState; - - if (this._config.userPoolId) { - const client_id = isCognitoHostedOpts(this._config.oauth) - ? this._config.userPoolWebClientId - : this._config.oauth.clientID; - /*Note: Invenstigate automatically adding trailing slash */ - const redirect_uri = isCognitoHostedOpts(this._config.oauth) - ? this._config.oauth.redirectSignIn - : this._config.oauth.redirectUri; - - this._oAuthHandler.oauthSignIn( - this._config.oauth.responseType, - this._config.oauth.domain, - redirect_uri, - client_id, - provider, - customState); - - } - } else { - - const provider = providerOrOptions; - // To check if the user is already logged in - try { - const loggedInUser = await this.currentAuthenticatedUser(); - logger.warn(`There is already a signed in user: ${loggedInUser} in your app. + private _config: AuthOptions; + private userPool = null; + private user: any = null; + private _oAuthHandler: OAuth; + private _storage; + private _storageSync; + + /** + * Initialize Auth with AWS configurations + * @param {Object} config - Configuration of the Auth + */ + constructor(config: AuthOptions) { + this.configure(config); + + this.currentUserCredentials = this.currentUserCredentials.bind(this); + + if (AWS.config) { + AWS.config.update({ customUserAgent: Constants.userAgent }); + } else { + logger.warn('No AWS.config'); + } + + Hub.listen('auth', ({ payload }) => { + const { event } = payload; + switch (event) { + case 'signIn': + this._storage.setItem('amplify-signin-with-hostedUI', 'false'); + break; + case 'signOut': + this._storage.removeItem('amplify-signin-with-hostedUI'); + break; + case 'cognitoHostedUI': + this._storage.setItem('amplify-signin-with-hostedUI', 'true'); + break; + } + }); + } + + public getModuleName() { + return 'Auth'; + } + + configure(config) { + if (!config) return this._config || {}; + logger.debug('configure Auth'); + const conf = Object.assign( + {}, + this._config, + Parser.parseMobilehubConfig(config).Auth, + config + ); + this._config = conf; + const { + userPoolId, + userPoolWebClientId, + cookieStorage, + oauth, + region, + identityPoolId, + mandatorySignIn, + refreshHandlers, + identityPoolRegion, + } = this._config; + + if (!this._config.storage) { + // backward compatbility + if (cookieStorage) this._storage = new CookieStorage(cookieStorage); + else { + this._storage = new StorageHelper().getStorage(); + } + } else { + if (!this._isValidAuthStorage(this._config.storage)) { + logger.error('The storage in the Auth config is not valid!'); + throw new Error('Empty storage object'); + } + this._storage = this._config.storage; + } + + this._storageSync = Promise.resolve(); + if (typeof this._storage['sync'] === 'function') { + this._storageSync = this._storage['sync'](); + } + + if (userPoolId) { + const userPoolData: ICognitoUserPoolData = { + UserPoolId: userPoolId, + ClientId: userPoolWebClientId, + }; + userPoolData.Storage = this._storage; + + this.userPool = new CognitoUserPool(userPoolData); + } + + Credentials.configure({ + mandatorySignIn, + region: identityPoolRegion || region, + userPoolId, + identityPoolId, + refreshHandlers, + storage: this._storage, + }); + + // initiailize cognitoauth client if hosted ui options provided + // to keep backward compatibility: + const cognitoHostedUIConfig = oauth + ? isCognitoHostedOpts(this._config.oauth) + ? oauth + : (oauth).awsCognito + : undefined; + + if (cognitoHostedUIConfig) { + const cognitoAuthParams = Object.assign( + { + cognitoClientId: userPoolWebClientId, + UserPoolId: userPoolId, + domain: cognitoHostedUIConfig['domain'], + scopes: cognitoHostedUIConfig['scope'], + redirectSignIn: cognitoHostedUIConfig['redirectSignIn'], + redirectSignOut: cognitoHostedUIConfig['redirectSignOut'], + responseType: cognitoHostedUIConfig['responseType'], + Storage: this._storage, + urlOpener: cognitoHostedUIConfig['urlOpener'], + }, + cognitoHostedUIConfig['options'] + ); + + this._oAuthHandler = new OAuth({ + scopes: cognitoAuthParams.scopes, + config: cognitoAuthParams, + cognitoClientId: cognitoAuthParams.cognitoClientId, + }); + + // **NOTE** - Remove this in a future major release as it is a breaking change + urlListener(({ url }) => { + this._handleAuthResponse(url); + }); + } + + dispatchAuthEvent( + 'configured', + null, + `The Auth category has been configured successfully` + ); + return this._config; + } + + /** + * Sign up with username, password and other attrbutes like phone, email + * @param {String | object} params - The user attirbutes used for signin + * @param {String[]} restOfAttrs - for the backward compatability + * @return - A promise resolves callback data if success + */ + public signUp( + params: string | SignUpParams, + ...restOfAttrs: string[] + ): Promise { + if (!this.userPool) { + return this.rejectNoUserPool(); + } + + let username: string = null; + let password: string = null; + const attributes: object[] = []; + let validationData: object[] = null; + + if (params && typeof params === 'string') { + username = params; + password = restOfAttrs ? restOfAttrs[0] : null; + const email: string = restOfAttrs ? restOfAttrs[1] : null; + const phone_number: string = restOfAttrs ? restOfAttrs[2] : null; + if (email) attributes.push({ Name: 'email', Value: email }); + if (phone_number) + attributes.push({ Name: 'phone_number', Value: phone_number }); + } else if (params && typeof params === 'object') { + username = params['username']; + password = params['password']; + const attrs = params['attributes']; + if (attrs) { + Object.keys(attrs).map(key => { + const ele: object = { Name: key, Value: attrs[key] }; + attributes.push(ele); + }); + } + validationData = params['validationData'] || null; + } else { + return this.rejectAuthError(AuthErrorTypes.SignUpError); + } + + if (!username) { + return this.rejectAuthError(AuthErrorTypes.EmptyUsername); + } + if (!password) { + return this.rejectAuthError(AuthErrorTypes.EmptyPassword); + } + + logger.debug('signUp attrs:', attributes); + logger.debug('signUp validation data:', validationData); + + return new Promise((resolve, reject) => { + this.userPool.signUp( + username, + password, + attributes, + validationData, + (err, data) => { + if (err) { + dispatchAuthEvent( + 'signUp_failure', + err, + `${username} failed to signup` + ); + reject(err); + } else { + dispatchAuthEvent( + 'signUp', + data, + `${username} has signed up successfully` + ); + resolve(data); + } + } + ); + }); + } + + /** + * Send the verfication code to confirm sign up + * @param {String} username - The username to be confirmed + * @param {String} code - The verification code + * @param {ConfirmSignUpOptions} options - other options for confirm signup + * @return - A promise resolves callback data if success + */ + public confirmSignUp( + username: string, + code: string, + options?: ConfirmSignUpOptions + ): Promise { + if (!this.userPool) { + return this.rejectNoUserPool(); + } + if (!username) { + return this.rejectAuthError(AuthErrorTypes.EmptyUsername); + } + if (!code) { + return this.rejectAuthError(AuthErrorTypes.EmptyCode); + } + + const user = this.createCognitoUser(username); + const forceAliasCreation = + options && typeof options.forceAliasCreation === 'boolean' + ? options.forceAliasCreation + : true; + + return new Promise((resolve, reject) => { + user.confirmRegistration(code, forceAliasCreation, (err, data) => { + if (err) { + reject(err); + } else { + resolve(data); + } + }); + }); + } + + /** + * Resend the verification code + * @param {String} username - The username to be confirmed + * @return - A promise resolves data if success + */ + public resendSignUp(username: string): Promise { + if (!this.userPool) { + return this.rejectNoUserPool(); + } + if (!username) { + return this.rejectAuthError(AuthErrorTypes.EmptyUsername); + } + + const user = this.createCognitoUser(username); + return new Promise((resolve, reject) => { + user.resendConfirmationCode((err, data) => { + if (err) { + reject(err); + } else { + resolve(data); + } + }); + }); + } + + /** + * Sign in + * @param {String | SignInOpts} usernameOrSignInOpts - The username to be signed in or the sign in options + * @param {String} password - The password of the username + * @return - A promise resolves the CognitoUser + */ + public signIn( + usernameOrSignInOpts: string | SignInOpts, + pw?: string + ): Promise { + if (!this.userPool) { + return this.rejectNoUserPool(); + } + let username = null; + let password = null; + let validationData = {}; + // for backward compatibility + if (typeof usernameOrSignInOpts === 'string') { + username = usernameOrSignInOpts; + password = pw; + } else if (isUsernamePasswordOpts(usernameOrSignInOpts)) { + if (typeof pw !== 'undefined') { + logger.warn( + 'The password should be defined under the first parameter object!' + ); + } + username = usernameOrSignInOpts.username; + password = usernameOrSignInOpts.password; + validationData = usernameOrSignInOpts.validationData; + } else { + return this.rejectAuthError(AuthErrorTypes.InvalidUsername); + } + if (!username) { + return this.rejectAuthError(AuthErrorTypes.EmptyUsername); + } + const authDetails = new AuthenticationDetails({ + Username: username, + Password: password, + ValidationData: validationData, + }); + if (password) { + return this.signInWithPassword(authDetails); + } else { + return this.signInWithoutPassword(authDetails); + } + } + + /** + * Return an object with the authentication callbacks + * @param {CognitoUser} user - the cognito user object + * @param {} resolve - function called when resolving the current step + * @param {} reject - function called when rejecting the current step + * @return - an object with the callback methods for user authentication + */ + private authCallbacks( + user: CognitoUser, + resolve: (value?: CognitoUser | any) => void, + reject: (value?: any) => void + ): IAuthenticationCallback { + const that = this; + return { + onSuccess: async session => { + logger.debug(session); + delete user['challengeName']; + delete user['challengeParam']; + try { + await Credentials.clear(); + const cred = await Credentials.set(session, 'session'); + logger.debug('succeed to get cognito credentials', cred); + } catch (e) { + logger.debug('cannot get cognito credentials', e); + } finally { + try { + // In order to get user attributes and MFA methods + // We need to trigger currentUserPoolUser again + const currentUser = await this.currentUserPoolUser(); + that.user = currentUser; + dispatchAuthEvent( + 'signIn', + currentUser, + `A user ${user.getUsername()} has been signed in` + ); + resolve(currentUser); + } catch (e) { + logger.error('Failed to get the signed in user', e); + reject(e); + } + } + }, + onFailure: err => { + logger.debug('signIn failure', err); + dispatchAuthEvent( + 'signIn_failure', + err, + `${user.getUsername()} failed to signin` + ); + reject(err); + }, + customChallenge: challengeParam => { + logger.debug('signIn custom challenge answer required'); + user['challengeName'] = 'CUSTOM_CHALLENGE'; + user['challengeParam'] = challengeParam; + resolve(user); + }, + mfaRequired: (challengeName, challengeParam) => { + logger.debug('signIn MFA required'); + user['challengeName'] = challengeName; + user['challengeParam'] = challengeParam; + resolve(user); + }, + mfaSetup: (challengeName, challengeParam) => { + logger.debug('signIn mfa setup', challengeName); + user['challengeName'] = challengeName; + user['challengeParam'] = challengeParam; + resolve(user); + }, + newPasswordRequired: (userAttributes, requiredAttributes) => { + logger.debug('signIn new password'); + user['challengeName'] = 'NEW_PASSWORD_REQUIRED'; + user['challengeParam'] = { + userAttributes, + requiredAttributes, + }; + resolve(user); + }, + totpRequired: (challengeName, challengeParam) => { + logger.debug('signIn totpRequired'); + user['challengeName'] = challengeName; + user['challengeParam'] = challengeParam; + resolve(user); + }, + selectMFAType: (challengeName, challengeParam) => { + logger.debug('signIn selectMFAType', challengeName); + user['challengeName'] = challengeName; + user['challengeParam'] = challengeParam; + resolve(user); + }, + }; + } + + /** + * Sign in with a password + * @private + * @param {AuthenticationDetails} authDetails - the user sign in data + * @return - A promise resolves the CognitoUser object if success or mfa required + */ + private signInWithPassword( + authDetails: AuthenticationDetails + ): Promise { + const user = this.createCognitoUser(authDetails.getUsername()); + + return new Promise((resolve, reject) => { + user.authenticateUser( + authDetails, + this.authCallbacks(user, resolve, reject) + ); + }); + } + + /** + * Sign in without a password + * @private + * @param {AuthenticationDetails} authDetails - the user sign in data + * @return - A promise resolves the CognitoUser object if success or mfa required + */ + private signInWithoutPassword( + authDetails: AuthenticationDetails + ): Promise { + const user = this.createCognitoUser(authDetails.getUsername()); + user.setAuthenticationFlowType('CUSTOM_AUTH'); + + return new Promise((resolve, reject) => { + user.initiateAuth(authDetails, this.authCallbacks(user, resolve, reject)); + }); + } + + /** + * get user current preferred mfa option + * this method doesn't work with totp, we need to deprecate it. + * @deprecated + * @param {CognitoUser} user - the current user + * @return - A promise resolves the current preferred mfa option if success + */ + public getMFAOptions(user: CognitoUser | any): Promise { + return new Promise((res, rej) => { + user.getMFAOptions((err, mfaOptions) => { + if (err) { + logger.debug('get MFA Options failed', err); + rej(err); + return; + } + logger.debug('get MFA options success', mfaOptions); + res(mfaOptions); + return; + }); + }); + } + + /** + * get preferred mfa method + * @param {CognitoUser} user - the current cognito user + * @param {GetPreferredMFAOpts} params - options for getting the current user preferred MFA + */ + public getPreferredMFA( + user: CognitoUser | any, + params?: GetPreferredMFAOpts + ): Promise { + const that = this; + return new Promise((res, rej) => { + const bypassCache = params ? params.bypassCache : false; + user.getUserData( + (err, data) => { + if (err) { + logger.debug('getting preferred mfa failed', err); + rej(err); + return; + } + + const mfaType = that._getMfaTypeFromUserData(data); + if (!mfaType) { + rej('invalid MFA Type'); + return; + } else { + res(mfaType); + return; + } + }, + { bypassCache } + ); + }); + } + + private _getMfaTypeFromUserData(data) { + let ret = null; + const preferredMFA = data.PreferredMfaSetting; + // if the user has used Auth.setPreferredMFA() to setup the mfa type + // then the "PreferredMfaSetting" would exist in the response + if (preferredMFA) { + ret = preferredMFA; + } else { + // if mfaList exists but empty, then its noMFA + const mfaList = data.UserMFASettingList; + if (!mfaList) { + // if SMS was enabled by using Auth.enableSMS(), + // the response would contain MFAOptions + // as for now Cognito only supports for SMS, so we will say it is 'SMS_MFA' + // if it does not exist, then it should be NOMFA + const MFAOptions = data.MFAOptions; + if (MFAOptions) { + ret = 'SMS_MFA'; + } else { + ret = 'NOMFA'; + } + } else if (mfaList.length === 0) { + ret = 'NOMFA'; + } else { + logger.debug('invalid case for getPreferredMFA', data); + } + } + return ret; + } + + private _getUserData(user, params) { + return new Promise((res, rej) => { + user.getUserData((err, data) => { + if (err) { + logger.debug('getting user data failed', err); + rej(err); + return; + } else { + res(data); + return; + } + }, params); + }); + } + + /** + * set preferred MFA method + * @param {CognitoUser} user - the current Cognito user + * @param {string} mfaMethod - preferred mfa method + * @return - A promise resolve if success + */ + public async setPreferredMFA( + user: CognitoUser | any, + mfaMethod: 'TOTP' | 'SMS' | 'NOMFA' + ): Promise { + const userData = await this._getUserData(user, { bypassCache: true }); + let smsMfaSettings = null; + let totpMfaSettings = null; + + switch (mfaMethod) { + case 'TOTP' || 'SOFTWARE_TOKEN_MFA': + totpMfaSettings = { + PreferredMfa: true, + Enabled: true, + }; + break; + case 'SMS' || 'SMS_MFA': + smsMfaSettings = { + PreferredMfa: true, + Enabled: true, + }; + break; + case 'NOMFA': + const mfaList = userData['UserMFASettingList']; + const currentMFAType = await this._getMfaTypeFromUserData(userData); + if (currentMFAType === 'NOMFA') { + return Promise.resolve('No change for mfa type'); + } else if (currentMFAType === 'SMS_MFA') { + smsMfaSettings = { + PreferredMfa: false, + Enabled: false, + }; + } else if (currentMFAType === 'SOFTWARE_TOKEN_MFA') { + totpMfaSettings = { + PreferredMfa: false, + Enabled: false, + }; + } else { + return this.rejectAuthError(AuthErrorTypes.InvalidMFA); + } + // if there is a UserMFASettingList in the response + // we need to disable every mfa type in that list + if (mfaList && mfaList.length !== 0) { + // to disable SMS or TOTP if exists in that list + mfaList.forEach(mfaType => { + if (mfaType === 'SMS_MFA') { + smsMfaSettings = { + PreferredMfa: false, + Enabled: false, + }; + } else if (mfaType === 'SOFTWARE_TOKEN_MFA') { + totpMfaSettings = { + PreferredMfa: false, + Enabled: false, + }; + } + }); + } + break; + default: + logger.debug('no validmfa method provided'); + return this.rejectAuthError(AuthErrorTypes.NoMFA); + } + + const that = this; + return new Promise((res, rej) => { + user.setUserMfaPreference( + smsMfaSettings, + totpMfaSettings, + (err, result) => { + if (err) { + logger.debug('Set user mfa preference error', err); + return rej(err); + } + logger.debug('Set user mfa success', result); + logger.debug('Caching the latest user data into local'); + // cache the latest result into user data + user.getUserData( + (err, data) => { + if (err) { + logger.debug('getting user data failed', err); + return rej(err); + } else { + return res(result); + } + }, + { bypassCache: true } + ); + } + ); + }); + } + + /** + * diable SMS + * @deprecated + * @param {CognitoUser} user - the current user + * @return - A promise resolves is success + */ + public disableSMS(user: CognitoUser): Promise { + return new Promise((res, rej) => { + user.disableMFA((err, data) => { + if (err) { + logger.debug('disable mfa failed', err); + rej(err); + return; + } + logger.debug('disable mfa succeed', data); + res(data); + return; + }); + }); + } + + /** + * enable SMS + * @deprecated + * @param {CognitoUser} user - the current user + * @return - A promise resolves is success + */ + public enableSMS(user: CognitoUser): Promise { + return new Promise((res, rej) => { + user.enableMFA((err, data) => { + if (err) { + logger.debug('enable mfa failed', err); + rej(err); + return; + } + logger.debug('enable mfa succeed', data); + res(data); + return; + }); + }); + } + + /** + * Setup TOTP + * @param {CognitoUser} user - the current user + * @return - A promise resolves with the secret code if success + */ + public setupTOTP(user: CognitoUser | any): Promise { + return new Promise((res, rej) => { + user.associateSoftwareToken({ + onFailure: err => { + logger.debug('associateSoftwareToken failed', err); + rej(err); + return; + }, + associateSecretCode: secretCode => { + logger.debug('associateSoftwareToken sucess', secretCode); + res(secretCode); + return; + }, + }); + }); + } + + /** + * verify TOTP setup + * @param {CognitoUser} user - the current user + * @param {string} challengeAnswer - challenge answer + * @return - A promise resolves is success + */ + public verifyTotpToken( + user: CognitoUser | any, + challengeAnswer: string + ): Promise { + logger.debug('verfication totp token', user, challengeAnswer); + return new Promise((res, rej) => { + user.verifySoftwareToken(challengeAnswer, 'My TOTP device', { + onFailure: err => { + logger.debug('verifyTotpToken failed', err); + rej(err); + return; + }, + onSuccess: data => { + logger.debug('verifyTotpToken success', data); + res(data); + return; + }, + }); + }); + } + + /** + * Send MFA code to confirm sign in + * @param {Object} user - The CognitoUser object + * @param {String} code - The confirmation code + */ + public confirmSignIn( + user: CognitoUser | any, + code: string, + mfaType?: 'SMS_MFA' | 'SOFTWARE_TOKEN_MFA' | null + ): Promise { + if (!code) { + return this.rejectAuthError(AuthErrorTypes.EmptyCode); + } + + const that = this; + return new Promise((resolve, reject) => { + user.sendMFACode( + code, + { + onSuccess: async session => { + logger.debug(session); + try { + await Credentials.clear(); + const cred = await Credentials.set(session, 'session'); + logger.debug('succeed to get cognito credentials', cred); + } catch (e) { + logger.debug('cannot get cognito credentials', e); + } finally { + that.user = user; + + dispatchAuthEvent('signIn', user, `${user} has signed in`); + resolve(user); + } + }, + onFailure: err => { + logger.debug('confirm signIn failure', err); + reject(err); + }, + }, + mfaType + ); + }); + } + + public completeNewPassword( + user: CognitoUser | any, + password: string, + requiredAttributes: any + ): Promise { + if (!password) { + return this.rejectAuthError(AuthErrorTypes.EmptyPassword); + } + + const that = this; + return new Promise((resolve, reject) => { + user.completeNewPasswordChallenge(password, requiredAttributes, { + onSuccess: async session => { + logger.debug(session); + try { + await Credentials.clear(); + const cred = await Credentials.set(session, 'session'); + logger.debug('succeed to get cognito credentials', cred); + } catch (e) { + logger.debug('cannot get cognito credentials', e); + } finally { + that.user = user; + dispatchAuthEvent('signIn', user, `${user} has signed in`); + resolve(user); + } + }, + onFailure: err => { + logger.debug('completeNewPassword failure', err); + dispatchAuthEvent( + 'completeNewPassword_failure', + err, + `${this.user} failed to complete the new password flow` + ); + reject(err); + }, + mfaRequired: (challengeName, challengeParam) => { + logger.debug('signIn MFA required'); + user['challengeName'] = challengeName; + user['challengeParam'] = challengeParam; + resolve(user); + }, + mfaSetup: (challengeName, challengeParam) => { + logger.debug('signIn mfa setup', challengeName); + user['challengeName'] = challengeName; + user['challengeParam'] = challengeParam; + resolve(user); + }, + }); + }); + } + + /** + * Send the answer to a custom challenge + * @param {CognitoUser} user - The CognitoUser object + * @param {String} challengeResponses - The confirmation code + */ + public sendCustomChallengeAnswer( + user: CognitoUser | any, + challengeResponses: string + ): Promise { + if (!this.userPool) { + return this.rejectNoUserPool(); + } + if (!challengeResponses) { + return this.rejectAuthError(AuthErrorTypes.EmptyChallengeResponse); + } + + const that = this; + return new Promise((resolve, reject) => { + user.sendCustomChallengeAnswer( + challengeResponses, + this.authCallbacks(user, resolve, reject) + ); + }); + } + + /** + * Update an authenticated users' attributes + * @param {CognitoUser} - The currently logged in user object + * @return {Promise} + **/ + public updateUserAttributes( + user: CognitoUser | any, + attributes: object + ): Promise { + const attributeList: ICognitoUserAttributeData[] = []; + const that = this; + return new Promise((resolve, reject) => { + that.userSession(user).then(session => { + for (const key in attributes) { + if (key !== 'sub' && key.indexOf('_verified') < 0) { + const attr: ICognitoUserAttributeData = { + Name: key, + Value: attributes[key], + }; + attributeList.push(attr); + } + } + user.updateAttributes(attributeList, (err, result) => { + if (err) { + return reject(err); + } else { + return resolve(result); + } + }); + }); + }); + } + /** + * Return user attributes + * @param {Object} user - The CognitoUser object + * @return - A promise resolves to user attributes if success + */ + public userAttributes( + user: CognitoUser | any + ): Promise { + return new Promise((resolve, reject) => { + this.userSession(user).then(session => { + user.getUserAttributes((err, attributes) => { + if (err) { + reject(err); + } else { + resolve(attributes); + } + }); + }); + }); + } + + public verifiedContact(user: CognitoUser | any) { + const that = this; + return this.userAttributes(user).then(attributes => { + const attrs = that.attributesToObject(attributes); + const unverified = {}; + const verified = {}; + if (attrs['email']) { + if (attrs['email_verified']) { + verified['email'] = attrs['email']; + } else { + unverified['email'] = attrs['email']; + } + } + if (attrs['phone_number']) { + if (attrs['phone_number_verified']) { + verified['phone_number'] = attrs['phone_number']; + } else { + unverified['phone_number'] = attrs['phone_number']; + } + } + return { + verified, + unverified, + }; + }); + } + + /** + * Get current authenticated user + * @return - A promise resolves to current authenticated CognitoUser if success + */ + public currentUserPoolUser( + params?: CurrentUserOpts + ): Promise { + if (!this.userPool) { + return this.rejectNoUserPool(); + } + const that = this; + return new Promise((res, rej) => { + this._storageSync + .then(() => { + const user = that.userPool.getCurrentUser(); + if (!user) { + logger.debug('Failed to get user from user pool'); + rej('No current user'); + return; + } + + // refresh the session if the session expired. + user.getSession((err, session) => { + if (err) { + logger.debug('Failed to get the user session', err); + rej(err); + return; + } + + // get user data from Cognito + const bypassCache = params ? params.bypassCache : false; + // validate the token's scope fisrt before calling this function + const { scope = '' } = session.getAccessToken().decodePayload(); + if (scope.split(' ').includes(USER_ADMIN_SCOPE)) { + user.getUserData( + (err, data) => { + if (err) { + logger.debug('getting user data failed', err); + // Make sure the user is still valid + if ( + err.message === 'User is disabled' || + err.message === 'User does not exist.' + ) { + rej(err); + } else { + // the error may also be thrown when lack of permissions to get user info etc + // in that case we just bypass the error + res(user); + } + return; + } + const preferredMFA = data.PreferredMfaSetting || 'NOMFA'; + const attributeList = []; + + for (let i = 0; i < data.UserAttributes.length; i++) { + const attribute = { + Name: data.UserAttributes[i].Name, + Value: data.UserAttributes[i].Value, + }; + const userAttribute = new CognitoUserAttribute(attribute); + attributeList.push(userAttribute); + } + + const attributes = that.attributesToObject(attributeList); + Object.assign(user, { attributes, preferredMFA }); + return res(user); + }, + { bypassCache } + ); + } else { + logger.debug( + `Unable to get the user data because the ${USER_ADMIN_SCOPE} ` + + `is not in the scopes of the access token` + ); + return res(user); + } + }); + }) + .catch(e => { + logger.debug('Failed to sync cache info into memory', e); + return rej(e); + }); + }); + } + + /** + * Get current authenticated user + * @param {CurrentUserOpts} - options for getting the current user + * @return - A promise resolves to current authenticated CognitoUser if success + */ + public async currentAuthenticatedUser( + params?: CurrentUserOpts + ): Promise { + logger.debug('getting current authenticated user'); + let federatedUser = null; + try { + await this._storageSync; + } catch (e) { + logger.debug('Failed to sync cache info into memory', e); + throw e; + } + + try { + federatedUser = JSON.parse( + this._storage.getItem('aws-amplify-federatedInfo') + ).user; + } catch (e) { + logger.debug('cannot load federated user from auth storage'); + } + + if (federatedUser) { + this.user = federatedUser; + logger.debug('get current authenticated federated user', this.user); + return this.user; + } else { + logger.debug('get current authenticated userpool user'); + let user = null; + try { + user = await this.currentUserPoolUser(params); + } catch (e) { + if (e === 'No userPool') { + logger.error( + 'Cannot get the current user because the user pool is missing. ' + + 'Please make sure the Auth module is configured with a valid Cognito User Pool ID' + ); + } + logger.debug('The user is not authenticated by the error', e); + throw 'not authenticated'; + } + this.user = user; + return this.user; + } + } + + /** + * Get current user's session + * @return - A promise resolves to session object if success + */ + public currentSession(): Promise { + const that = this; + logger.debug('Getting current session'); + // Purposely not calling the reject method here because we don't need a console error + if (!this.userPool) { + return Promise.reject(); + } + + return new Promise((res, rej) => { + that + .currentUserPoolUser() + .then(user => { + that + .userSession(user) + .then(session => { + res(session); + return; + }) + .catch(e => { + logger.debug('Failed to get the current session', e); + rej(e); + return; + }); + }) + .catch(e => { + logger.debug('Failed to get the current user', e); + rej(e); + return; + }); + }); + } + + /** + * Get the corresponding user session + * @param {Object} user - The CognitoUser object + * @return - A promise resolves to the session + */ + public userSession(user): Promise { + if (!user) { + logger.debug('the user is null'); + return this.rejectAuthError(AuthErrorTypes.NoUserSession); + } + return new Promise((resolve, reject) => { + logger.debug('Getting the session from this user:', user); + user.getSession((err, session) => { + if (err) { + logger.debug('Failed to get the session from user', user); + reject(err); + return; + } else { + logger.debug('Succeed to get the user session', session); + resolve(session); + return; + } + }); + }); + } + + /** + * Get authenticated credentials of current user. + * @return - A promise resolves to be current user's credentials + */ + public async currentUserCredentials(): Promise { + const that = this; + logger.debug('Getting current user credentials'); + + try { + await this._storageSync; + } catch (e) { + logger.debug('Failed to sync cache info into memory', e); + throw e; + } + + // first to check whether there is federation info in the auth storage + let federatedInfo = null; + try { + federatedInfo = JSON.parse( + this._storage.getItem('aws-amplify-federatedInfo') + ); + } catch (e) { + logger.debug('failed to get or parse item aws-amplify-federatedInfo', e); + } + + if (federatedInfo) { + // refresh the jwt token here if necessary + return Credentials.refreshFederatedToken(federatedInfo); + } else { + return this.currentSession() + .then(session => { + logger.debug('getting session success', session); + return Credentials.set(session, 'session'); + }) + .catch(error => { + logger.debug('getting session failed', error); + return Credentials.set(null, 'guest'); + }); + } + } + + public currentCredentials(): Promise { + logger.debug('getting current credntials'); + return Credentials.get(); + } + + /** + * Initiate an attribute confirmation request + * @param {Object} user - The CognitoUser + * @param {Object} attr - The attributes to be verified + * @return - A promise resolves to callback data if success + */ + public verifyUserAttribute( + user: CognitoUser | any, + attr: string + ): Promise { + return new Promise((resolve, reject) => { + user.getAttributeVerificationCode(attr, { + onSuccess() { + return resolve(); + }, + onFailure(err) { + return reject(err); + }, + }); + }); + } + + /** + * Confirm an attribute using a confirmation code + * @param {Object} user - The CognitoUser + * @param {Object} attr - The attribute to be verified + * @param {String} code - The confirmation code + * @return - A promise resolves to callback data if success + */ + public verifyUserAttributeSubmit( + user: CognitoUser | any, + attr: string, + code: string + ): Promise { + if (!code) { + return this.rejectAuthError(AuthErrorTypes.EmptyCode); + } + + return new Promise((resolve, reject) => { + user.verifyAttribute(attr, code, { + onSuccess(data) { + resolve(data); + return; + }, + onFailure(err) { + reject(err); + return; + }, + }); + }); + } + + public verifyCurrentUserAttribute(attr: string): Promise { + const that = this; + return that + .currentUserPoolUser() + .then(user => that.verifyUserAttribute(user, attr)); + } + + /** + * Confirm current user's attribute using a confirmation code + * @param {Object} attr - The attribute to be verified + * @param {String} code - The confirmation code + * @return - A promise resolves to callback data if success + */ + verifyCurrentUserAttributeSubmit( + attr: string, + code: string + ): Promise { + const that = this; + return that + .currentUserPoolUser() + .then(user => that.verifyUserAttributeSubmit(user, attr, code)); + } + + private async cognitoIdentitySignOut( + opts: SignOutOpts, + user: CognitoUser | any + ) { + try { + await this._storageSync; + } catch (e) { + logger.debug('Failed to sync cache info into memory', e); + throw e; + } + + const isSignedInHostedUI = + this._oAuthHandler && + this._storage.getItem('amplify-signin-with-hostedUI') === 'true'; + + return new Promise((res, rej) => { + if (opts && opts.global) { + logger.debug('user global sign out', user); + // in order to use global signout + // we must validate the user as an authenticated user by using getSession + user.getSession((err, result) => { + if (err) { + logger.debug('failed to get the user session', err); + return rej(err); + } + user.globalSignOut({ + onSuccess: data => { + logger.debug('global sign out success'); + if (isSignedInHostedUI) { + return res(this._oAuthHandler.signOut()); + } else { + return res(); + } + }, + onFailure: err => { + logger.debug('global sign out failed', err); + return rej(err); + }, + }); + }); + } else { + logger.debug('user sign out', user); + user.signOut(); + if (isSignedInHostedUI) { + return res(this._oAuthHandler.signOut()); + } else { + return res(); + } + } + }); + } + + /** + * Sign out method + * @ + * @return - A promise resolved if success + */ + public async signOut(opts?: SignOutOpts): Promise { + try { + await this.cleanCachedItems(); + } catch (e) { + logger.debug('failed to clear cached items'); + } + + if (this.userPool) { + const user = this.userPool.getCurrentUser(); + if (user) { + await this.cognitoIdentitySignOut(opts, user); + } else { + logger.debug('no current Cognito user'); + } + } else { + logger.debug('no Congito User pool'); + } + + /** + * Note for future refactor - no reliable way to get username with + * Cognito User Pools vs Identity when federating with Social Providers + * This is why we need a well structured session object that can be inspected + * and information passed back in the message below for Hub dispatch + */ + dispatchAuthEvent('signOut', this.user, `A user has been signed out`); + this.user = null; + } + + private async cleanCachedItems() { + // clear cognito cached item + await Credentials.clear(); + } + + /** + * Change a password for an authenticated user + * @param {Object} user - The CognitoUser object + * @param {String} oldPassword - the current password + * @param {String} newPassword - the requested new password + * @return - A promise resolves if success + */ + public changePassword( + user: CognitoUser | any, + oldPassword: string, + newPassword: string + ): Promise<'SUCCESS'> { + return new Promise((resolve, reject) => { + this.userSession(user).then(session => { + user.changePassword(oldPassword, newPassword, (err, data) => { + if (err) { + logger.debug('change password failure', err); + return reject(err); + } else { + return resolve(data); + } + }); + }); + }); + } + + /** + * Initiate a forgot password request + * @param {String} username - the username to change password + * @return - A promise resolves if success + */ + public forgotPassword(username: string): Promise { + if (!this.userPool) { + return this.rejectNoUserPool(); + } + if (!username) { + return this.rejectAuthError(AuthErrorTypes.EmptyUsername); + } + + const user = this.createCognitoUser(username); + return new Promise((resolve, reject) => { + user.forgotPassword({ + onSuccess: () => { + resolve(); + return; + }, + onFailure: err => { + logger.debug('forgot password failure', err); + reject(err); + return; + }, + inputVerificationCode: data => { + resolve(data); + return; + }, + }); + }); + } + + /** + * Confirm a new password using a confirmation Code + * @param {String} username - The username + * @param {String} code - The confirmation code + * @param {String} password - The new password + * @return - A promise that resolves if success + */ + public forgotPasswordSubmit( + username: string, + code: string, + password: string + ): Promise { + if (!this.userPool) { + return this.rejectNoUserPool(); + } + if (!username) { + return this.rejectAuthError(AuthErrorTypes.EmptyUsername); + } + if (!code) { + return this.rejectAuthError(AuthErrorTypes.EmptyCode); + } + if (!password) { + return this.rejectAuthError(AuthErrorTypes.EmptyPassword); + } + + const user = this.createCognitoUser(username); + return new Promise((resolve, reject) => { + user.confirmPassword(code, password, { + onSuccess: () => { + resolve(); + return; + }, + onFailure: err => { + reject(err); + return; + }, + }); + }); + } + + /** + * Get user information + * @async + * @return {Object }- current User's information + */ + public async currentUserInfo() { + const source = Credentials.getCredSource(); + + if (!source || source === 'aws' || source === 'userPool') { + const user = await this.currentUserPoolUser().catch(err => + logger.debug(err) + ); + if (!user) { + return null; + } + + try { + const attributes = await this.userAttributes(user); + const userAttrs: object = this.attributesToObject(attributes); + let credentials = null; + try { + credentials = await this.currentCredentials(); + } catch (e) { + logger.debug( + 'Failed to retrieve credentials while getting current user info', + e + ); + } + + const info = { + id: credentials ? credentials.identityId : undefined, + username: user.getUsername(), + attributes: userAttrs, + }; + return info; + } catch (err) { + logger.debug('currentUserInfo error', err); + return {}; + } + } + + if (source === 'federated') { + const user = this.user; + return user ? user : {}; + } + } + + public async federatedSignIn( + options?: FederatedSignInOptions + ): Promise; + public async federatedSignIn( + provider: LegacyProvider, + response: FederatedResponse, + user: FederatedUser + ): Promise; + public async federatedSignIn( + options?: FederatedSignInOptionsCustom + ): Promise; + public async federatedSignIn( + providerOrOptions: + | LegacyProvider + | FederatedSignInOptions + | FederatedSignInOptionsCustom, + response?: FederatedResponse, + user?: FederatedUser + ): Promise { + if (!this._config.identityPoolId && !this._config.userPoolId) { + throw new Error( + `Federation requires either a User Pool or Identity Pool in config` + ); + } + + // Ensure backwards compatability + if (typeof providerOrOptions === 'undefined') { + if (this._config.identityPoolId && !this._config.userPoolId) { + throw new Error( + `Federation with Identity Pools requires tokens passed as arguments` + ); + } + } + + if ( + isFederatedSignInOptions(providerOrOptions) || + isFederatedSignInOptionsCustom(providerOrOptions) || + typeof providerOrOptions === 'undefined' + ) { + const options = providerOrOptions || { + provider: CognitoHostedUIIdentityProvider.Cognito, + }; + const provider = isFederatedSignInOptions(options) + ? options.provider + : (options as FederatedSignInOptionsCustom).customProvider; + + const customState = isFederatedSignInOptions(options) + ? options.customState + : (options as FederatedSignInOptionsCustom).customState; + + if (this._config.userPoolId) { + const client_id = isCognitoHostedOpts(this._config.oauth) + ? this._config.userPoolWebClientId + : this._config.oauth.clientID; + /*Note: Invenstigate automatically adding trailing slash */ + const redirect_uri = isCognitoHostedOpts(this._config.oauth) + ? this._config.oauth.redirectSignIn + : this._config.oauth.redirectUri; + + this._oAuthHandler.oauthSignIn( + this._config.oauth.responseType, + this._config.oauth.domain, + redirect_uri, + client_id, + provider, + customState + ); + } + } else { + const provider = providerOrOptions; + // To check if the user is already logged in + try { + const loggedInUser = await this.currentAuthenticatedUser(); + logger.warn(`There is already a signed in user: ${loggedInUser} in your app. You should not call Auth.federatedSignIn method again as it may cause unexpected behavior.`); - } catch (e) { } - - const { token, identity_id, expires_at } = response; - // Because Credentials.set would update the user info with identity id - // So we need to retrieve the user again. - const credentials = await Credentials.set( - { provider, token, identity_id, user, expires_at }, - 'federation' - ); - const currentUser = await this.currentAuthenticatedUser(); - dispatchAuthEvent( - 'signIn', - currentUser, - `A user ${currentUser.username} has been signed in` - ); - logger.debug('federated sign in credentials', credentials); - return credentials; - } - } - - /** - * Used to complete the OAuth flow with or without the Cognito Hosted UI - * @param {String} URL - optional parameter for customers to pass in the response URL - */ - private async _handleAuthResponse(URL?: string) { - - if (!this._config.userPoolId){ - throw new Error(`OAuth responses require a User Pool defined in config`); - } - - dispatchAuthEvent( - 'parsingCallbackUrl', - { url: URL }, - `The callback url is being parsed` - ); - - const currentUrl = URL || (JS.browserOrNode().isBrowser ? window.location.href : ''); - - const hasCodeOrError = !!(parse(currentUrl).query || '') - .split('&') - .map(entry => entry.split('=')) - .find(([k]) => k === 'code' || k === 'error'); - - const hasTokenOrError = !!(parse(currentUrl).hash || '#') - .substr(1) - .split('&') - .map(entry => entry.split('=')) - .find(([k]) => k === 'access_token' || k === 'error'); - - - if (hasCodeOrError || hasTokenOrError) { - try { - - const { - accessToken, - idToken, - refreshToken, - state } = await this._oAuthHandler.handleAuthResponse(currentUrl); - const session = new CognitoUserSession({ - IdToken: new CognitoIdToken({ IdToken: idToken }), - RefreshToken: new CognitoRefreshToken({ RefreshToken: refreshToken }), - AccessToken: new CognitoAccessToken({ AccessToken: accessToken }) - }); - - let credentials; - // Get AWS Credentials & store if Identity Pool is defined - if (this._config.identityPoolId) { - credentials = await Credentials.set(session, 'session'); - logger.debug('AWS credentials', credentials); - } - - /* + } catch (e) {} + + const { token, identity_id, expires_at } = response; + // Because Credentials.set would update the user info with identity id + // So we need to retrieve the user again. + const credentials = await Credentials.set( + { provider, token, identity_id, user, expires_at }, + 'federation' + ); + const currentUser = await this.currentAuthenticatedUser(); + dispatchAuthEvent( + 'signIn', + currentUser, + `A user ${currentUser.username} has been signed in` + ); + logger.debug('federated sign in credentials', credentials); + return credentials; + } + } + + /** + * Used to complete the OAuth flow with or without the Cognito Hosted UI + * @param {String} URL - optional parameter for customers to pass in the response URL + */ + private async _handleAuthResponse(URL?: string) { + if (!this._config.userPoolId) { + throw new Error(`OAuth responses require a User Pool defined in config`); + } + + dispatchAuthEvent( + 'parsingCallbackUrl', + { url: URL }, + `The callback url is being parsed` + ); + + const currentUrl = + URL || (JS.browserOrNode().isBrowser ? window.location.href : ''); + + const hasCodeOrError = !!(parse(currentUrl).query || '') + .split('&') + .map(entry => entry.split('=')) + .find(([k]) => k === 'code' || k === 'error'); + + const hasTokenOrError = !!(parse(currentUrl).hash || '#') + .substr(1) + .split('&') + .map(entry => entry.split('=')) + .find(([k]) => k === 'access_token' || k === 'error'); + + if (hasCodeOrError || hasTokenOrError) { + try { + const { + accessToken, + idToken, + refreshToken, + state, + } = await this._oAuthHandler.handleAuthResponse(currentUrl); + const session = new CognitoUserSession({ + IdToken: new CognitoIdToken({ IdToken: idToken }), + RefreshToken: new CognitoRefreshToken({ RefreshToken: refreshToken }), + AccessToken: new CognitoAccessToken({ AccessToken: accessToken }), + }); + + let credentials; + // Get AWS Credentials & store if Identity Pool is defined + if (this._config.identityPoolId) { + credentials = await Credentials.set(session, 'session'); + logger.debug('AWS credentials', credentials); + } + + /* Prior to the request we do sign the custom state along with the state we set. This check will verify if there is a dash indicated when setting custom state from the request. If a dash is contained then there is custom state present on the state string. */ - const isCustomStateIncluded = /-/.test(state); + const isCustomStateIncluded = /-/.test(state); - /*The following is to create a user for the Cognito Identity SDK to store the tokens + /*The following is to create a user for the Cognito Identity SDK to store the tokens When we remove this SDK later that logic will have to be centralized in our new version*/ - //#region - const currentUser = this.createCognitoUser(session.getIdToken().decodePayload()['cognito:username']); - dispatchAuthEvent( - 'signIn', - currentUser, - `A user ${currentUser.getUsername()} has been signed in` - ); - dispatchAuthEvent( - 'cognitoHostedUI', - currentUser, - `A user ${currentUser.getUsername()} has been signed in via Cognito Hosted UI` - ); - - if (isCustomStateIncluded) { - const [, customState] = state.split('-'); - - dispatchAuthEvent( - 'customOAuthState', - customState, - `State for user ${currentUser.getUsername()}` - ); - } - - // This calls cacheTokens() in Cognito SDK - currentUser.setSignInUserSession(session); - //#endregion - - if (window && typeof window.history !== 'undefined') { - window.history.replaceState({}, null, (this._config.oauth as AwsCognitoOAuthOpts).redirectSignIn); - } - - return credentials; - } catch (err) { - logger.debug("Error in cognito hosted auth response", err); - dispatchAuthEvent( - 'signIn_failure', - err, - `The OAuth response flow failed` - ); - dispatchAuthEvent( - 'cognitoHostedUI_failure', - err, - `A failure occurred when returning to the Cognito Hosted UI` - ); - dispatchAuthEvent( - 'customState_failure', - err, - `A failure occurred when returning state` - ); - throw err; - } - } - - } - - /** - * Compact version of credentials - * @param {Object} credentials - * @return {Object} - Credentials - */ - public essentialCredentials(credentials): ICredentials { - return { - accessKeyId: credentials.accessKeyId, - sessionToken: credentials.sessionToken, - secretAccessKey: credentials.secretAccessKey, - identityId: credentials.identityId, - authenticated: credentials.authenticated - }; - } - - private attributesToObject(attributes) { - const obj = {}; - if (attributes) { - attributes.map(attribute => { - if (attribute.Value === 'true') { - obj[attribute.Name] = true; - } else if (attribute.Value === 'false') { - obj[attribute.Name] = false; - } else { - obj[attribute.Name] = attribute.Value; - } - }); - } - return obj; - } - - private createCognitoUser(username: string): CognitoUser { - const userData: ICognitoUserData = { - Username: username, - Pool: this.userPool, - }; - userData.Storage = this._storage; - - const { authenticationFlowType } = this._config; - - const user = new CognitoUser(userData); - if (authenticationFlowType) { - user.setAuthenticationFlowType(authenticationFlowType); - } - return user; - } - - private _isValidAuthStorage(obj) { - // We need to check if the obj has the functions of Storage - return !!obj && - typeof obj.getItem === 'function' && - typeof obj.setItem === 'function' && - typeof obj.removeItem === 'function' && - typeof obj.clear === 'function'; - } - - private noUserPoolErrorHandler(config: AuthOptions): AuthErrorTypes { - if (config) { - if (!config.userPoolId || !config.identityPoolId) { - return AuthErrorTypes.MissingAuthConfig; - } - } - return AuthErrorTypes.NoConfig; - } - - private rejectAuthError(type: AuthErrorTypes): Promise { - return Promise.reject(new AuthError(type)); - } - - private rejectNoUserPool(): Promise { - const type = this.noUserPoolErrorHandler(this._config); - return Promise.reject(new NoUserPoolError(type)); - } + //#region + const currentUser = this.createCognitoUser( + session.getIdToken().decodePayload()['cognito:username'] + ); + dispatchAuthEvent( + 'signIn', + currentUser, + `A user ${currentUser.getUsername()} has been signed in` + ); + dispatchAuthEvent( + 'cognitoHostedUI', + currentUser, + `A user ${currentUser.getUsername()} has been signed in via Cognito Hosted UI` + ); + + if (isCustomStateIncluded) { + const [, customState] = state.split('-'); + + dispatchAuthEvent( + 'customOAuthState', + customState, + `State for user ${currentUser.getUsername()}` + ); + } + + // This calls cacheTokens() in Cognito SDK + currentUser.setSignInUserSession(session); + //#endregion + + if (window && typeof window.history !== 'undefined') { + window.history.replaceState( + {}, + null, + (this._config.oauth as AwsCognitoOAuthOpts).redirectSignIn + ); + } + + return credentials; + } catch (err) { + logger.debug('Error in cognito hosted auth response', err); + dispatchAuthEvent( + 'signIn_failure', + err, + `The OAuth response flow failed` + ); + dispatchAuthEvent( + 'cognitoHostedUI_failure', + err, + `A failure occurred when returning to the Cognito Hosted UI` + ); + dispatchAuthEvent( + 'customState_failure', + err, + `A failure occurred when returning state` + ); + throw err; + } + } + } + + /** + * Compact version of credentials + * @param {Object} credentials + * @return {Object} - Credentials + */ + public essentialCredentials(credentials): ICredentials { + return { + accessKeyId: credentials.accessKeyId, + sessionToken: credentials.sessionToken, + secretAccessKey: credentials.secretAccessKey, + identityId: credentials.identityId, + authenticated: credentials.authenticated, + }; + } + + private attributesToObject(attributes) { + const obj = {}; + if (attributes) { + attributes.map(attribute => { + if (attribute.Value === 'true') { + obj[attribute.Name] = true; + } else if (attribute.Value === 'false') { + obj[attribute.Name] = false; + } else { + obj[attribute.Name] = attribute.Value; + } + }); + } + return obj; + } + + private createCognitoUser(username: string): CognitoUser { + const userData: ICognitoUserData = { + Username: username, + Pool: this.userPool, + }; + userData.Storage = this._storage; + + const { authenticationFlowType } = this._config; + + const user = new CognitoUser(userData); + if (authenticationFlowType) { + user.setAuthenticationFlowType(authenticationFlowType); + } + return user; + } + + private _isValidAuthStorage(obj) { + // We need to check if the obj has the functions of Storage + return ( + !!obj && + typeof obj.getItem === 'function' && + typeof obj.setItem === 'function' && + typeof obj.removeItem === 'function' && + typeof obj.clear === 'function' + ); + } + + private noUserPoolErrorHandler(config: AuthOptions): AuthErrorTypes { + if (config) { + if (!config.userPoolId || !config.identityPoolId) { + return AuthErrorTypes.MissingAuthConfig; + } + } + return AuthErrorTypes.NoConfig; + } + + private rejectAuthError(type: AuthErrorTypes): Promise { + return Promise.reject(new AuthError(type)); + } + + private rejectNoUserPool(): Promise { + const type = this.noUserPoolErrorHandler(this._config); + return Promise.reject(new NoUserPoolError(type)); + } } diff --git a/packages/auth/src/Errors.ts b/packages/auth/src/Errors.ts index 0426b660ac0..be8af2f214a 100644 --- a/packages/auth/src/Errors.ts +++ b/packages/auth/src/Errors.ts @@ -18,40 +18,40 @@ const logger = new Logger('AuthError'); const DEFAULT_MSG = 'Authentication Error'; export class AuthError extends Error { - public log: string; - constructor(type: AuthErrorTypes) { - const { message, log } = authErrorMessages[type]; - super(message); + public log: string; + constructor(type: AuthErrorTypes) { + const { message, log } = authErrorMessages[type]; + super(message); - // Hack for making the custom error class work when transpiled to es5 - // TODO: Delete the following 2 lines after we change the build target to >= es2015 - this.constructor = AuthError; - Object.setPrototypeOf(this, AuthError.prototype); + // Hack for making the custom error class work when transpiled to es5 + // TODO: Delete the following 2 lines after we change the build target to >= es2015 + this.constructor = AuthError; + Object.setPrototypeOf(this, AuthError.prototype); - this.name = 'AuthError'; - this.log = log || message; + this.name = 'AuthError'; + this.log = log || message; - logger.error(this.log); - } + logger.error(this.log); + } } export class NoUserPoolError extends AuthError { - constructor(type: AuthErrorTypes) { - super(type); + constructor(type: AuthErrorTypes) { + super(type); - // Hack for making the custom error class work when transpiled to es5 - // TODO: Delete the following 2 lines after we change the build target to >= es2015 - this.constructor = NoUserPoolError; - Object.setPrototypeOf(this, NoUserPoolError.prototype); + // Hack for making the custom error class work when transpiled to es5 + // TODO: Delete the following 2 lines after we change the build target to >= es2015 + this.constructor = NoUserPoolError; + Object.setPrototypeOf(this, NoUserPoolError.prototype); - this.name = 'NoUserPoolError'; - } + this.name = 'NoUserPoolError'; + } } export const authErrorMessages: AuthErrorMessages = { - noConfig: { - message: DEFAULT_MSG, - log: ` + noConfig: { + message: DEFAULT_MSG, + log: ` Error: Amplify has not been configured correctly. This error is typically caused by one of the following scenarios: @@ -60,48 +60,48 @@ export const authErrorMessages: AuthErrorMessages = { 2. There might be multiple conflicting versions of aws-amplify or amplify packages in your node_modules. Try deleting your node_modules folder and reinstalling the dependencies with \`yarn install\` - ` - }, - missingAuthConfig: { - message: DEFAULT_MSG, - log: ` + `, + }, + missingAuthConfig: { + message: DEFAULT_MSG, + log: ` Error: Amplify has not been configured correctly. The configuration object is missing required auth properties. Did you run \`amplify push\` after adding auth via \`amplify add auth\`? See https://aws-amplify.github.io/docs/js/authentication#amplify-project-setup for more information - ` - }, - emptyUsername: { - message: 'Username cannot be empty' - }, - // TODO: should include a list of valid sign-in types - invalidUsername: { - message: - 'The username should either be a string or one of the sign in types' - }, - emptyPassword: { - message: 'Password cannot be empty' - }, - emptyCode: { - message: 'Confirmation code cannot be empty' - }, - signUpError: { - message: 'Error creating account', - log: 'The first parameter should either be non-null string or object' - }, - noMFA: { - message: 'No valid MFA method provided' - }, - invalidMFA: { - message: 'Invalid MFA type' - }, - emptyChallengeResponse: { - message: 'Challenge response cannot be empty' - }, - noUserSession: { - message: 'Failed to get the session because the user is empty' - }, - default: { - message: DEFAULT_MSG - } + `, + }, + emptyUsername: { + message: 'Username cannot be empty', + }, + // TODO: should include a list of valid sign-in types + invalidUsername: { + message: + 'The username should either be a string or one of the sign in types', + }, + emptyPassword: { + message: 'Password cannot be empty', + }, + emptyCode: { + message: 'Confirmation code cannot be empty', + }, + signUpError: { + message: 'Error creating account', + log: 'The first parameter should either be non-null string or object', + }, + noMFA: { + message: 'No valid MFA method provided', + }, + invalidMFA: { + message: 'Invalid MFA type', + }, + emptyChallengeResponse: { + message: 'Challenge response cannot be empty', + }, + noUserSession: { + message: 'Failed to get the session because the user is empty', + }, + default: { + message: DEFAULT_MSG, + }, }; diff --git a/packages/auth/src/OAuth/OAuth.ts b/packages/auth/src/OAuth/OAuth.ts index 411f7a2d609..06f031ed99e 100644 --- a/packages/auth/src/OAuth/OAuth.ts +++ b/packages/auth/src/OAuth/OAuth.ts @@ -11,284 +11,309 @@ * and limitations under the License. */ - -import { parse } from 'url'; // Used for OAuth parsing of Cognito Hosted UI +import { parse } from 'url'; // Used for OAuth parsing of Cognito Hosted UI import { launchUri } from './urlOpener'; import * as oAuthStorage from './oauthStorage'; import { - OAuthOpts, - isCognitoHostedOpts, - CognitoHostedUIIdentityProvider + OAuthOpts, + isCognitoHostedOpts, + CognitoHostedUIIdentityProvider, } from '../types/Auth'; -import { - ConsoleLogger as Logger, - Hub -} from '@aws-amplify/core'; +import { ConsoleLogger as Logger, Hub } from '@aws-amplify/core'; -const SHA256 = require("crypto-js/sha256"); -const Base64 = require("crypto-js/enc-base64"); +const SHA256 = require('crypto-js/sha256'); +const Base64 = require('crypto-js/enc-base64'); -const AMPLIFY_SYMBOL = ((typeof Symbol !== 'undefined' && typeof Symbol.for === 'function') ? - Symbol.for('amplify_default') : '@@amplify_default') as Symbol; +const AMPLIFY_SYMBOL = (typeof Symbol !== 'undefined' && +typeof Symbol.for === 'function' + ? Symbol.for('amplify_default') + : '@@amplify_default') as Symbol; -const dispatchAuthEvent = (event:string, data:any, message:string) => { - Hub.dispatch('auth', { event, data, message }, 'Auth', AMPLIFY_SYMBOL); +const dispatchAuthEvent = (event: string, data: any, message: string) => { + Hub.dispatch('auth', { event, data, message }, 'Auth', AMPLIFY_SYMBOL); }; const logger = new Logger('OAuth'); export default class OAuth { - - private _urlOpener; - private _config; - private _cognitoClientId; - private _scopes; - - constructor({ - config, - cognitoClientId, - scopes = [] - }: { - scopes: string[], - config: OAuthOpts, - cognitoClientId: string - }) { - this._urlOpener = config.urlOpener || launchUri; - this._config = config; - this._cognitoClientId = cognitoClientId; - this._scopes = scopes; - } - - public oauthSignIn( - responseType = 'code', - domain: string, - redirectSignIn: string, - clientId: string, - provider: CognitoHostedUIIdentityProvider | string = CognitoHostedUIIdentityProvider.Cognito, - customState?: string) { - - const generatedState = this._generateState(32); - const state = customState ? `${generatedState}-${customState}` : generatedState; - - oAuthStorage.setState(encodeURIComponent(state)); - - const pkce_key = this._generateRandom(128); - oAuthStorage.setPKCE(pkce_key); - - const code_challenge = this._generateChallenge(pkce_key); - const code_challenge_method = 'S256'; - - const queryString = Object.entries({ - redirect_uri: redirectSignIn, - response_type: responseType, - client_id: clientId, - identity_provider: provider, - scopes: this._scopes, - state, - ...(responseType === 'code'?{code_challenge}:{}), - ...(responseType === 'code'?{code_challenge_method}:{}) - }).map(([k,v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&'); - - const URL = `https://${domain}/oauth2/authorize?${queryString}`; - logger.debug(`Redirecting to ${URL}`); - this._urlOpener(URL, redirectSignIn); - } - - private async _handleCodeFlow(currentUrl: string) { - /* Convert URL into an object with parameters as keys + private _urlOpener; + private _config; + private _cognitoClientId; + private _scopes; + + constructor({ + config, + cognitoClientId, + scopes = [], + }: { + scopes: string[]; + config: OAuthOpts; + cognitoClientId: string; + }) { + this._urlOpener = config.urlOpener || launchUri; + this._config = config; + this._cognitoClientId = cognitoClientId; + this._scopes = scopes; + } + + public oauthSignIn( + responseType = 'code', + domain: string, + redirectSignIn: string, + clientId: string, + provider: + | CognitoHostedUIIdentityProvider + | string = CognitoHostedUIIdentityProvider.Cognito, + customState?: string + ) { + const generatedState = this._generateState(32); + const state = customState + ? `${generatedState}-${customState}` + : generatedState; + + oAuthStorage.setState(encodeURIComponent(state)); + + const pkce_key = this._generateRandom(128); + oAuthStorage.setPKCE(pkce_key); + + const code_challenge = this._generateChallenge(pkce_key); + const code_challenge_method = 'S256'; + + const queryString = Object.entries({ + redirect_uri: redirectSignIn, + response_type: responseType, + client_id: clientId, + identity_provider: provider, + scopes: this._scopes, + state, + ...(responseType === 'code' ? { code_challenge } : {}), + ...(responseType === 'code' ? { code_challenge_method } : {}), + }) + .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`) + .join('&'); + + const URL = `https://${domain}/oauth2/authorize?${queryString}`; + logger.debug(`Redirecting to ${URL}`); + this._urlOpener(URL, redirectSignIn); + } + + private async _handleCodeFlow(currentUrl: string) { + /* Convert URL into an object with parameters as keys { redirect_uri: 'http://localhost:3000/', response_type: 'code', ...} */ - const { code } = (parse(currentUrl).query || '') - .split('&') - .map((pairings) => pairings.split('=')) - .reduce((accum, [k, v]) => ({ ...accum, [k]: v }), { code: undefined }); - - if (!code) { return; } - - - const oAuthTokenEndpoint = 'https://' + this._config.domain + '/oauth2/token'; - - dispatchAuthEvent( - 'codeFlow', - {}, - `Retrieving tokens from ${oAuthTokenEndpoint}` - ); - - const client_id = isCognitoHostedOpts(this._config) - ? this._cognitoClientId - : this._config.clientID; - - const redirect_uri = isCognitoHostedOpts(this._config) - ? this._config.redirectSignIn - : this._config.redirectUri; - - const code_verifier = oAuthStorage.getPKCE(); - - const oAuthTokenBody = { - grant_type: 'authorization_code', - code, - client_id, - redirect_uri, - ...(code_verifier ? { code_verifier } : {}) - }; - - logger.debug(`Calling token endpoint: ${oAuthTokenEndpoint} with`, oAuthTokenBody); - - const body = Object.entries(oAuthTokenBody) - .map(([k, v]) =>`${encodeURIComponent(k)}=${encodeURIComponent(v)}`) - .join('&'); - - const { access_token, refresh_token, id_token, error } = await (await fetch(oAuthTokenEndpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - }, - body - }) as any).json(); - - if (error) { - throw new Error(error); - } - - return { - accessToken: access_token, - refreshToken: refresh_token, - idToken: id_token - }; - } - - private async _handleImplicitFlow(currentUrl: string) { - - const { id_token, access_token } = parse(currentUrl).hash - .substr(1) // Remove # from returned code - .split('&') - .map((pairings) => pairings.split('=')) - .reduce((accum, [k, v]) => ({ ...accum, [k]: v }), { - id_token: undefined, access_token: undefined - }); - - dispatchAuthEvent( - 'implicitFlow', - {}, - `Got tokens from ${currentUrl}` - ); - logger.debug(`Retrieving implicit tokens from ${currentUrl} with`); - - return { - accessToken: access_token, - idToken: id_token, - refreshToken: null - }; - } - - public async handleAuthResponse(currentUrl?: string) { - try { - const urlParams = currentUrl ? { - ...(parse(currentUrl).hash || '#').substr(1) - .split('&') - .map(entry => entry.split('=')) - .reduce((acc, [k, v]) => (acc[k] = v, acc), {}), - ...(parse(currentUrl).query || '') - .split('&') - .map(entry => entry.split('=')) - .reduce((acc, [k, v]) => (acc[k] = v, acc), {}) - } as any : {}; - const { error, error_description } = urlParams; - - if (error) { - throw new Error(error_description); - } - - const state: string = this._validateState(urlParams); - - logger.debug(`Starting ${this._config.responseType} flow with ${currentUrl}`); - if (this._config.responseType === 'code') { - return {...await this._handleCodeFlow(currentUrl), state}; - } else { - return {...await this._handleImplicitFlow(currentUrl), state}; - } - } catch (e) { - logger.error(`Error handling auth response.`, e); - } - } - - private _validateState(urlParams: any): string { - if (!urlParams) { return; } - - const savedState = oAuthStorage.getState(); - const { state: returnedState } = urlParams; - - // This is because savedState only exists if the flow was initiated by Amplify - if (savedState && savedState !== returnedState) { - throw new Error('Invalid state in OAuth flow'); - } - return returnedState; - } - - public async signOut() { - let oAuthLogoutEndpoint = 'https://' + this._config.domain + '/logout?'; - - const client_id = isCognitoHostedOpts(this._config) - ? this._cognitoClientId - : this._config.oauth.clientID; - - const signout_uri = isCognitoHostedOpts(this._config) - ? this._config.redirectSignOut - : this._config.returnTo; - - oAuthLogoutEndpoint += Object.entries({ - client_id, - logout_uri: encodeURIComponent(signout_uri) - }).map(([k, v]) => `${k}=${v}`).join('&'); - - dispatchAuthEvent( - 'oAuthSignOut', - {oAuth: 'signOut'}, - `Signing out from ${oAuthLogoutEndpoint}` - ); - logger.debug(`Signing out from ${oAuthLogoutEndpoint}`); - - return this._urlOpener(oAuthLogoutEndpoint); - } - - private _generateState(length: number) { - let result = ''; - let i = length; - const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - for (; i > 0; --i) result += chars[Math.round(Math.random() * (chars.length - 1))]; - return result; - } - - private _generateChallenge(code:string) { - return this._base64URL(SHA256(code)); - } - - private _base64URL(string) { - return string.toString(Base64).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); - } - - private _generateRandom(size: number) { - const CHARSET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'; - const buffer = new Uint8Array(size); - if (typeof window !== 'undefined' && !!(window.crypto)) { - window.crypto.getRandomValues(buffer); - } else { - for (let i = 0; i < size; i += 1) { - buffer[i] = (Math.random() * CHARSET.length) | 0; - } - } - return this._bufferToString(buffer); - } - - private _bufferToString(buffer: Uint8Array) { - const CHARSET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - const state = []; - for (let i = 0; i < buffer.byteLength; i += 1) { - const index = buffer[i] % CHARSET.length; - state.push(CHARSET[index]); - } - return state.join(''); - } + const { code } = (parse(currentUrl).query || '') + .split('&') + .map(pairings => pairings.split('=')) + .reduce((accum, [k, v]) => ({ ...accum, [k]: v }), { code: undefined }); + + if (!code) { + return; + } + + const oAuthTokenEndpoint = + 'https://' + this._config.domain + '/oauth2/token'; + + dispatchAuthEvent( + 'codeFlow', + {}, + `Retrieving tokens from ${oAuthTokenEndpoint}` + ); + + const client_id = isCognitoHostedOpts(this._config) + ? this._cognitoClientId + : this._config.clientID; + + const redirect_uri = isCognitoHostedOpts(this._config) + ? this._config.redirectSignIn + : this._config.redirectUri; + + const code_verifier = oAuthStorage.getPKCE(); + + const oAuthTokenBody = { + grant_type: 'authorization_code', + code, + client_id, + redirect_uri, + ...(code_verifier ? { code_verifier } : {}), + }; + + logger.debug( + `Calling token endpoint: ${oAuthTokenEndpoint} with`, + oAuthTokenBody + ); + + const body = Object.entries(oAuthTokenBody) + .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`) + .join('&'); + + const { + access_token, + refresh_token, + id_token, + error, + } = await ((await fetch(oAuthTokenEndpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body, + })) as any).json(); + + if (error) { + throw new Error(error); + } + + return { + accessToken: access_token, + refreshToken: refresh_token, + idToken: id_token, + }; + } + + private async _handleImplicitFlow(currentUrl: string) { + const { id_token, access_token } = parse(currentUrl) + .hash.substr(1) // Remove # from returned code + .split('&') + .map(pairings => pairings.split('=')) + .reduce((accum, [k, v]) => ({ ...accum, [k]: v }), { + id_token: undefined, + access_token: undefined, + }); + + dispatchAuthEvent('implicitFlow', {}, `Got tokens from ${currentUrl}`); + logger.debug(`Retrieving implicit tokens from ${currentUrl} with`); + + return { + accessToken: access_token, + idToken: id_token, + refreshToken: null, + }; + } + + public async handleAuthResponse(currentUrl?: string) { + try { + const urlParams = currentUrl + ? ({ + ...(parse(currentUrl).hash || '#') + .substr(1) + .split('&') + .map(entry => entry.split('=')) + .reduce((acc, [k, v]) => ((acc[k] = v), acc), {}), + ...(parse(currentUrl).query || '') + .split('&') + .map(entry => entry.split('=')) + .reduce((acc, [k, v]) => ((acc[k] = v), acc), {}), + } as any) + : {}; + const { error, error_description } = urlParams; + + if (error) { + throw new Error(error_description); + } + + const state: string = this._validateState(urlParams); + + logger.debug( + `Starting ${this._config.responseType} flow with ${currentUrl}` + ); + if (this._config.responseType === 'code') { + return { ...(await this._handleCodeFlow(currentUrl)), state }; + } else { + return { ...(await this._handleImplicitFlow(currentUrl)), state }; + } + } catch (e) { + logger.error(`Error handling auth response.`, e); + } + } + + private _validateState(urlParams: any): string { + if (!urlParams) { + return; + } + + const savedState = oAuthStorage.getState(); + const { state: returnedState } = urlParams; + + // This is because savedState only exists if the flow was initiated by Amplify + if (savedState && savedState !== returnedState) { + throw new Error('Invalid state in OAuth flow'); + } + return returnedState; + } + + public async signOut() { + let oAuthLogoutEndpoint = 'https://' + this._config.domain + '/logout?'; + + const client_id = isCognitoHostedOpts(this._config) + ? this._cognitoClientId + : this._config.oauth.clientID; + + const signout_uri = isCognitoHostedOpts(this._config) + ? this._config.redirectSignOut + : this._config.returnTo; + + oAuthLogoutEndpoint += Object.entries({ + client_id, + logout_uri: encodeURIComponent(signout_uri), + }) + .map(([k, v]) => `${k}=${v}`) + .join('&'); + + dispatchAuthEvent( + 'oAuthSignOut', + { oAuth: 'signOut' }, + `Signing out from ${oAuthLogoutEndpoint}` + ); + logger.debug(`Signing out from ${oAuthLogoutEndpoint}`); + + return this._urlOpener(oAuthLogoutEndpoint); + } + + private _generateState(length: number) { + let result = ''; + let i = length; + const chars = + '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + for (; i > 0; --i) + result += chars[Math.round(Math.random() * (chars.length - 1))]; + return result; + } + + private _generateChallenge(code: string) { + return this._base64URL(SHA256(code)); + } + + private _base64URL(string) { + return string + .toString(Base64) + .replace(/=/g, '') + .replace(/\+/g, '-') + .replace(/\//g, '_'); + } + + private _generateRandom(size: number) { + const CHARSET = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'; + const buffer = new Uint8Array(size); + if (typeof window !== 'undefined' && !!window.crypto) { + window.crypto.getRandomValues(buffer); + } else { + for (let i = 0; i < size; i += 1) { + buffer[i] = (Math.random() * CHARSET.length) | 0; + } + } + return this._bufferToString(buffer); + } + + private _bufferToString(buffer: Uint8Array) { + const CHARSET = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const state = []; + for (let i = 0; i < buffer.byteLength; i += 1) { + const index = buffer[i] % CHARSET.length; + state.push(CHARSET[index]); + } + return state.join(''); + } } - diff --git a/packages/auth/src/OAuth/oauthStorage.native.ts b/packages/auth/src/OAuth/oauthStorage.native.ts index 2216234dfe1..86b10a8cbb6 100644 --- a/packages/auth/src/OAuth/oauthStorage.native.ts +++ b/packages/auth/src/OAuth/oauthStorage.native.ts @@ -11,32 +11,32 @@ * and limitations under the License. */ -const obj:{ - oauth_state?: string, - ouath_pkce_key?: string +const obj: { + oauth_state?: string; + ouath_pkce_key?: string; } = {}; -export const setState = (state:string) =>{ - obj.oauth_state = state; +export const setState = (state: string) => { + obj.oauth_state = state; }; export const getState = () => { - const oauth_state = obj.oauth_state; - obj.oauth_state = undefined; - return oauth_state; + const oauth_state = obj.oauth_state; + obj.oauth_state = undefined; + return oauth_state; }; -export const setPKCE = (private_key:string) =>{ - obj.ouath_pkce_key = private_key; +export const setPKCE = (private_key: string) => { + obj.ouath_pkce_key = private_key; }; export const getPKCE = () => { - const ouath_pkce_key = obj.ouath_pkce_key; - obj.ouath_pkce_key = undefined; - return ouath_pkce_key; + const ouath_pkce_key = obj.ouath_pkce_key; + obj.ouath_pkce_key = undefined; + return ouath_pkce_key; }; export const clearAll = () => { - obj.ouath_pkce_key = undefined; - obj.oauth_state = undefined; + obj.ouath_pkce_key = undefined; + obj.oauth_state = undefined; }; diff --git a/packages/auth/src/OAuth/oauthStorage.ts b/packages/auth/src/OAuth/oauthStorage.ts index 7cb59e79d2b..43d36aa518e 100644 --- a/packages/auth/src/OAuth/oauthStorage.ts +++ b/packages/auth/src/OAuth/oauthStorage.ts @@ -11,27 +11,27 @@ * and limitations under the License. */ -export const setState = (state:string) =>{ - window.sessionStorage.setItem('oauth_state', state); +export const setState = (state: string) => { + window.sessionStorage.setItem('oauth_state', state); }; export const getState = () => { - const oauth_state = window.sessionStorage.getItem('oauth_state'); - window.sessionStorage.removeItem('oauth_state'); - return oauth_state; + const oauth_state = window.sessionStorage.getItem('oauth_state'); + window.sessionStorage.removeItem('oauth_state'); + return oauth_state; }; -export const setPKCE = (private_key:string) =>{ - window.sessionStorage.setItem('ouath_pkce_key', private_key); +export const setPKCE = (private_key: string) => { + window.sessionStorage.setItem('ouath_pkce_key', private_key); }; export const getPKCE = () => { - const ouath_pkce_key = window.sessionStorage.getItem('ouath_pkce_key'); - window.sessionStorage.removeItem('ouath_pkce_key'); - return ouath_pkce_key; + const ouath_pkce_key = window.sessionStorage.getItem('ouath_pkce_key'); + window.sessionStorage.removeItem('ouath_pkce_key'); + return ouath_pkce_key; }; export const clearAll = () => { - window.sessionStorage.removeItem('ouath_pkce_key'); - window.sessionStorage.removeItem('oauth_state'); + window.sessionStorage.removeItem('ouath_pkce_key'); + window.sessionStorage.removeItem('oauth_state'); }; diff --git a/packages/auth/src/OAuth/urlOpener.native.ts b/packages/auth/src/OAuth/urlOpener.native.ts index 635a223d8a4..5a79e2d0425 100644 --- a/packages/auth/src/OAuth/urlOpener.native.ts +++ b/packages/auth/src/OAuth/urlOpener.native.ts @@ -13,4 +13,4 @@ import { Linking } from 'react-native'; -export const launchUri = (url) => Linking.openURL(url); +export const launchUri = url => Linking.openURL(url); diff --git a/packages/auth/src/OAuth/urlOpener.ts b/packages/auth/src/OAuth/urlOpener.ts index 41cc71e8e83..d22bab50e94 100644 --- a/packages/auth/src/OAuth/urlOpener.ts +++ b/packages/auth/src/OAuth/urlOpener.ts @@ -13,11 +13,11 @@ const SELF = '_self'; -export const launchUri = (url) => { - const windowProxy = window.open(url, SELF); - if (windowProxy) { - return Promise.resolve(windowProxy); - } else { - return Promise.reject(); - } +export const launchUri = url => { + const windowProxy = window.open(url, SELF); + if (windowProxy) { + return Promise.resolve(windowProxy); + } else { + return Promise.reject(); + } }; diff --git a/packages/auth/src/index.ts b/packages/auth/src/index.ts index 1638223e29f..850cdcc77b0 100644 --- a/packages/auth/src/index.ts +++ b/packages/auth/src/index.ts @@ -12,7 +12,7 @@ */ import AuthClass, { CognitoHostedUIIdentityProvider } from './Auth'; -import { CognitoUser, CookieStorage, }from 'amazon-cognito-identity-js'; +import { CognitoUser, CookieStorage } from 'amazon-cognito-identity-js'; import Amplify, { ConsoleLogger as Logger } from '@aws-amplify/core'; const logger = new Logger('Auth'); @@ -20,12 +20,17 @@ const logger = new Logger('Auth'); let _instance: AuthClass = null; if (!_instance) { - logger.debug('Create Auth Instance'); - _instance = new AuthClass(null); + logger.debug('Create Auth Instance'); + _instance = new AuthClass(null); } const Auth = _instance; Amplify.register(Auth); export default Auth; -export { AuthClass, CognitoUser, CookieStorage, CognitoHostedUIIdentityProvider }; +export { + AuthClass, + CognitoUser, + CookieStorage, + CognitoHostedUIIdentityProvider, +}; diff --git a/packages/auth/src/types/Auth.ts b/packages/auth/src/types/Auth.ts index 2766b86fe1c..a7b39a200f1 100644 --- a/packages/auth/src/types/Auth.ts +++ b/packages/auth/src/types/Auth.ts @@ -12,138 +12,138 @@ */ import { - ICookieStorageData, - ICognitoStorage, - CognitoUserAttribute + ICookieStorageData, + ICognitoStorage, + CognitoUserAttribute, } from 'amazon-cognito-identity-js'; /** * Parameters for user sign up */ export interface SignUpParams { - username: string; - password: string; - attributes?: object; - validationData?: CognitoUserAttribute[]; + username: string; + password: string; + attributes?: object; + validationData?: CognitoUserAttribute[]; } export interface AuthCache { - setItem(); - getItem(); - removeItem(); + setItem(); + getItem(); + removeItem(); } /** * Auth instance options */ export interface AuthOptions { - userPoolId?: string; - userPoolWebClientId?: string; - identityPoolId?: string; - region?: string; - mandatorySignIn?: boolean; - cookieStorage?: ICookieStorageData; - oauth?: OAuthOpts; - refreshHandlers?: object; - storage?: ICognitoStorage; - authenticationFlowType?: string; - identityPoolRegion?: string; + userPoolId?: string; + userPoolWebClientId?: string; + identityPoolId?: string; + region?: string; + mandatorySignIn?: boolean; + cookieStorage?: ICookieStorageData; + oauth?: OAuthOpts; + refreshHandlers?: object; + storage?: ICognitoStorage; + authenticationFlowType?: string; + identityPoolRegion?: string; } export enum CognitoHostedUIIdentityProvider { - Cognito = 'COGNITO', - Google = 'Google', - Facebook = 'Facebook', - Amazon = 'LoginWithAmazon' + Cognito = 'COGNITO', + Google = 'Google', + Facebook = 'Facebook', + Amazon = 'LoginWithAmazon', } export type LegacyProvider = - | 'google' - | 'facebook' - | 'amazon' - | 'developer' - | string; + | 'google' + | 'facebook' + | 'amazon' + | 'developer' + | string; export type FederatedSignInOptions = { - provider: CognitoHostedUIIdentityProvider; - customState?: string; + provider: CognitoHostedUIIdentityProvider; + customState?: string; }; export type FederatedSignInOptionsCustom = { - customProvider: string; - customState?: string; + customProvider: string; + customState?: string; }; export function isFederatedSignInOptions( - obj: any + obj: any ): obj is FederatedSignInOptions { - const keys: (keyof FederatedSignInOptions)[] = ['provider', 'customState']; - return obj && !!keys.find(k => obj.hasOwnProperty(k)); + const keys: (keyof FederatedSignInOptions)[] = ['provider', 'customState']; + return obj && !!keys.find(k => obj.hasOwnProperty(k)); } export function isFederatedSignInOptionsCustom( - obj: any + obj: any ): obj is FederatedSignInOptionsCustom { - const keys: (keyof FederatedSignInOptionsCustom)[] = [ - 'customProvider', - 'customState' - ]; - return obj && !!keys.find(k => obj.hasOwnProperty(k)); + const keys: (keyof FederatedSignInOptionsCustom)[] = [ + 'customProvider', + 'customState', + ]; + return obj && !!keys.find(k => obj.hasOwnProperty(k)); } /** * Details for multi-factor authentication */ export interface MfaRequiredDetails { - challengeName: any; - challengeParameters: any; + challengeName: any; + challengeParameters: any; } /** * interface for federatedResponse */ export interface FederatedResponse { - // access token - token: string; - // identity id - identity_id?: string; - // the universal time when token expired - expires_at: number; + // access token + token: string; + // identity id + identity_id?: string; + // the universal time when token expired + expires_at: number; } /** * interface for federatedUser */ export interface FederatedUser { - name: string; - email?: string; + name: string; + email?: string; } export interface AwsCognitoOAuthOpts { - domain: string; - scope: Array; - redirectSignIn: string; - redirectSignOut: string; - responseType: string; - options?: object; - urlOpener?: (url: string, redirectUrl: string) => Promise; + domain: string; + scope: Array; + redirectSignIn: string; + redirectSignOut: string; + responseType: string; + options?: object; + urlOpener?: (url: string, redirectUrl: string) => Promise; } export function isCognitoHostedOpts( - oauth: OAuthOpts + oauth: OAuthOpts ): oauth is AwsCognitoOAuthOpts { - return (oauth).redirectSignIn !== undefined; + return (oauth).redirectSignIn !== undefined; } export interface Auth0OAuthOpts { - domain: string; - clientID: string; - scope: string; - redirectUri: string; - audience: string; - responseType: string; - returnTo: string; - urlOpener?: (url: string, redirectUrl: string) => Promise; + domain: string; + clientID: string; + scope: string; + redirectUri: string; + audience: string; + responseType: string; + returnTo: string; + urlOpener?: (url: string, redirectUrl: string) => Promise; } // Replacing to fix typings @@ -155,52 +155,52 @@ export interface Auth0OAuthOpts { export type OAuthOpts = AwsCognitoOAuthOpts | Auth0OAuthOpts; export interface ConfirmSignUpOptions { - forceAliasCreation?: boolean; + forceAliasCreation?: boolean; } export interface SignOutOpts { - global?: boolean; + global?: boolean; } export interface CurrentUserOpts { - bypassCache: boolean; + bypassCache: boolean; } export interface GetPreferredMFAOpts { - bypassCache: boolean; + bypassCache: boolean; } export type UsernamePasswordOpts = { - username: string; - password: string; - validationData?: { [key: string]: any }; + username: string; + password: string; + validationData?: { [key: string]: any }; }; export enum AuthErrorTypes { - NoConfig = 'noConfig', - MissingAuthConfig = 'missingAuthConfig', - EmptyUsername = 'emptyUsername', - InvalidUsername = 'invalidUsername', - EmptyPassword = 'emptyPassword', - EmptyCode = 'emptyCode', - SignUpError = 'signUpError', - NoMFA = 'noMFA', - InvalidMFA = 'invalidMFA', - EmptyChallengeResponse = 'emptyChallengeResponse', - NoUserSession = 'noUserSession', - Default = 'default' + NoConfig = 'noConfig', + MissingAuthConfig = 'missingAuthConfig', + EmptyUsername = 'emptyUsername', + InvalidUsername = 'invalidUsername', + EmptyPassword = 'emptyPassword', + EmptyCode = 'emptyCode', + SignUpError = 'signUpError', + NoMFA = 'noMFA', + InvalidMFA = 'invalidMFA', + EmptyChallengeResponse = 'emptyChallengeResponse', + NoUserSession = 'noUserSession', + Default = 'default', } export type AuthErrorMessages = { [key in AuthErrorTypes]: AuthErrorMessage }; export interface AuthErrorMessage { - message: string; - log?: string; + message: string; + log?: string; } // We can extend this in the future if needed export type SignInOpts = UsernamePasswordOpts; export function isUsernamePasswordOpts(obj: any): obj is UsernamePasswordOpts { - return !!(obj as UsernamePasswordOpts).username; + return !!(obj as UsernamePasswordOpts).username; } diff --git a/packages/auth/src/urlListener.native.ts b/packages/auth/src/urlListener.native.ts index 45143da8c90..61f053b350e 100644 --- a/packages/auth/src/urlListener.native.ts +++ b/packages/auth/src/urlListener.native.ts @@ -10,37 +10,38 @@ * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ -import { - ConsoleLogger as Logger -} from '@aws-amplify/core'; +import { ConsoleLogger as Logger } from '@aws-amplify/core'; const logger = new Logger('urlListener'); let handler; export default async callback => { - if (handler) { - return; - } + if (handler) { + return; + } - let Linking: any; - let AppState: any; + let Linking: any; + let AppState: any; - try { - ({ Linking, AppState } = require('react-native')); - } catch (error) { /* Keep webpack happy */ } + try { + ({ Linking, AppState } = require('react-native')); + } catch (error) { + /* Keep webpack happy */ + } + handler = + handler || + (({ url, ...rest }: { url: string }) => { + logger.debug('urlListener', { url, ...rest }); + callback({ url }); + }); - handler = handler || (({ url, ...rest }: { url: string }) => { - logger.debug('urlListener', { url, ...rest }); - callback({ url }); - }); - - Linking.removeEventListener('url', handler); - Linking.addEventListener('url', handler); - AppState.addEventListener('change', async newAppState => { - if (newAppState === 'active') { - const initialUrl = await Linking.getInitialURL(); - handler({ url: initialUrl }); - } - }); + Linking.removeEventListener('url', handler); + Linking.addEventListener('url', handler); + AppState.addEventListener('change', async newAppState => { + if (newAppState === 'active') { + const initialUrl = await Linking.getInitialURL(); + handler({ url: initialUrl }); + } + }); }; diff --git a/packages/auth/src/urlListener.ts b/packages/auth/src/urlListener.ts index dfbbf02ec3a..2857e997d00 100644 --- a/packages/auth/src/urlListener.ts +++ b/packages/auth/src/urlListener.ts @@ -10,19 +10,17 @@ * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ -import { - JS, -} from '@aws-amplify/core'; +import { JS } from '@aws-amplify/core'; export default callback => { - if (JS.browserOrNode().isBrowser && window.location) { - const url = window.location.href; + if (JS.browserOrNode().isBrowser && window.location) { + const url = window.location.href; - callback({ url }); - } else if (JS.browserOrNode().isNode) { - // continue building on ssr - () => {}; // noop - } else { - throw new Error('Not supported'); - } + callback({ url }); + } else if (JS.browserOrNode().isNode) { + // continue building on ssr + () => {}; // noop + } else { + throw new Error('Not supported'); + } }; diff --git a/packages/auth/tslint.json b/packages/auth/tslint.json index 9d5f01d0502..1bb9e144d24 100644 --- a/packages/auth/tslint.json +++ b/packages/auth/tslint.json @@ -1,72 +1,45 @@ - { - "defaultSeverity": "error", - "plugins": [ - "prettier" - ], - "extends": [ - //"tslint-config-airbnb" - ], - "jsRules": {}, - "rules": { - "prefer-const": true, - "max-line-length": [true, 120], - "no-empty-interface": true, - "no-var-keyword": true, - "object-literal-shorthand": true, - "no-eval": true, - "space-before-function-paren": [ - true, - { - "anonymous": "never", - "named": "never" - } - ], - "no-parameter-reassignment": true, - "align": [ - true, - "arguments", - "parameters" - ], - "no-duplicate-imports": true, - "one-variable-per-declaration": [ - false, - "ignore-for-loop" - ], - "triple-equals": [ - true, - "allow-null-check" - ], - "no-boolean-literal-compare": true, - "comment-format": [ - true, - "check-space" - ], - "indent": [ - true, - "space", - 2 - ], - "whitespace": [ - false, - "check-branch", - "check-decl", - "check-operator", - "check-preblock" - ], - "eofline": true, - "variable-name": [ - true, - "check-format", // 22.2 - "allow-pascal-case", - "allow-snake-case", - "allow-leading-underscore" - ], - "semicolon": [ - true, - "always", - "ignore-interfaces" - ] - }, - "rulesDirectory": [] -} \ No newline at end of file + "defaultSeverity": "error", + "plugins": ["prettier"], + "extends": [], + "jsRules": {}, + "rules": { + "prefer-const": true, + "max-line-length": [true, 120], + "no-empty-interface": true, + "no-var-keyword": true, + "object-literal-shorthand": true, + "no-eval": true, + "space-before-function-paren": [ + true, + { + "anonymous": "never", + "named": "never" + } + ], + "no-parameter-reassignment": true, + "align": [true, "parameters"], + "no-duplicate-imports": true, + "one-variable-per-declaration": [false, "ignore-for-loop"], + "triple-equals": [true, "allow-null-check"], + "comment-format": [true, "check-space"], + "indent": [false], + "whitespace": [ + false, + "check-branch", + "check-decl", + "check-operator", + "check-preblock" + ], + "eofline": true, + "variable-name": [ + true, + "check-format", + "allow-pascal-case", + "allow-snake-case", + "allow-leading-underscore" + ], + "semicolon": [true, "always", "ignore-interfaces"] + }, + "rulesDirectory": [] +} diff --git a/packages/auth/webpack.config.js b/packages/auth/webpack.config.js index 70fcc104152..7a97e3e87a3 100644 --- a/packages/auth/webpack.config.js +++ b/packages/auth/webpack.config.js @@ -1,59 +1,60 @@ const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); -const CompressionPlugin = require("compression-webpack-plugin") +const CompressionPlugin = require('compression-webpack-plugin'); module.exports = { - entry: { - 'aws-amplify-auth': './src/index.ts', - 'aws-amplify-auth.min': './src/index.ts' - }, - externals: { - 'react-native': 'react-native' - }, - output: { - filename: '[name].js', - path: __dirname + '/dist', - library: 'aws_amplify_auth', - libraryTarget: 'umd', - umdNamedDefine: true, - devtoolModuleFilenameTemplate: require('../aws-amplify/webpack-utils').devtoolModuleFilenameTemplate - }, - // Enable sourcemaps for debugging webpack's output. - devtool: 'source-map', - resolve: { - // Add '.ts' and '.tsx' as resolvable extensions. - extensions: ['.ts', '.tsx', '.js', '.json'] - }, - plugins: [ - new UglifyJsPlugin({ - minimize: true, - sourceMap: true, - include: /\.min\.js$/, - }), - new CompressionPlugin({ - include: /\.min\.js$/, - }) - ], - module: { - rules: [ - // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'. - { - test: /\.tsx?$/, - loader: 'awesome-typescript-loader', - exclude: /node_modules/, - query: { - declaration: false - } - }, - // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. - //{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' }, - { - test: /\.jsx?$/, - exclude: /node_modules/, - loader: 'babel-loader', - query: { - presets: ['react', 'es2015', 'stage-2'], - } - } - ] - } + entry: { + 'aws-amplify-auth': './src/index.ts', + 'aws-amplify-auth.min': './src/index.ts', + }, + externals: { + 'react-native': 'react-native', + }, + output: { + filename: '[name].js', + path: __dirname + '/dist', + library: 'aws_amplify_auth', + libraryTarget: 'umd', + umdNamedDefine: true, + devtoolModuleFilenameTemplate: require('../aws-amplify/webpack-utils') + .devtoolModuleFilenameTemplate, + }, + // Enable sourcemaps for debugging webpack's output. + devtool: 'source-map', + resolve: { + // Add '.ts' and '.tsx' as resolvable extensions. + extensions: ['.ts', '.tsx', '.js', '.json'], + }, + plugins: [ + new UglifyJsPlugin({ + minimize: true, + sourceMap: true, + include: /\.min\.js$/, + }), + new CompressionPlugin({ + include: /\.min\.js$/, + }), + ], + module: { + rules: [ + // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'. + { + test: /\.tsx?$/, + loader: 'awesome-typescript-loader', + exclude: /node_modules/, + query: { + declaration: false, + }, + }, + // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. + //{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' }, + { + test: /\.jsx?$/, + exclude: /node_modules/, + loader: 'babel-loader', + query: { + presets: ['react', 'es2015', 'stage-2'], + }, + }, + ], + }, }; diff --git a/packages/aws-amplify-angular/CHANGELOG.md b/packages/aws-amplify-angular/CHANGELOG.md index c761a694866..1b1358d2c0b 100644 --- a/packages/aws-amplify-angular/CHANGELOG.md +++ b/packages/aws-amplify-angular/CHANGELOG.md @@ -7,1888 +7,1405 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package aws-amplify-angular - - - - ## [3.0.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.12...aws-amplify-angular@3.0.13) (2019-09-05) **Note:** Version bump only for package aws-amplify-angular - - - - ## [3.0.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.11...aws-amplify-angular@3.0.12) (2019-09-04) **Note:** Version bump only for package aws-amplify-angular - - - - ## [3.0.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.10...aws-amplify-angular@3.0.11) (2019-08-05) **Note:** Version bump only for package aws-amplify-angular - - - - ## [3.0.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.9...aws-amplify-angular@3.0.10) (2019-08-01) **Note:** Version bump only for package aws-amplify-angular - - - - ## [3.0.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.8...aws-amplify-angular@3.0.9) (2019-07-31) **Note:** Version bump only for package aws-amplify-angular - - - - ## [3.0.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.7...aws-amplify-angular@3.0.8) (2019-07-30) **Note:** Version bump only for package aws-amplify-angular - - - - ## [3.0.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.5...aws-amplify-angular@3.0.7) (2019-07-18) **Note:** Version bump only for package aws-amplify-angular - - - - -## [3.0.6-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.6-unstable.2...aws-amplify-angular@3.0.6-unstable.3) (2019-07-12) - - +## [3.0.6-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.6-unstable.2...aws-amplify-angular@3.0.6-unstable.3) (2019-07-12) **Note:** Version bump only for package aws-amplify-angular -## [3.0.6-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.6-unstable.0...aws-amplify-angular@3.0.6-unstable.2) (2019-07-12) - - +## [3.0.6-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.6-unstable.0...aws-amplify-angular@3.0.6-unstable.2) (2019-07-12) **Note:** Version bump only for package aws-amplify-angular -## [3.0.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.5...aws-amplify-angular@3.0.6-unstable.0) (2019-07-10) - - +## [3.0.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.5...aws-amplify-angular@3.0.6-unstable.0) (2019-07-10) **Note:** Version bump only for package aws-amplify-angular -## [3.0.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.5-unstable.2...aws-amplify-angular@3.0.5) (2019-07-09) - - +## [3.0.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.5-unstable.2...aws-amplify-angular@3.0.5) (2019-07-09) **Note:** Version bump only for package aws-amplify-angular -## [3.0.5-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.5-unstable.1...aws-amplify-angular@3.0.5-unstable.2) (2019-07-09) - - +## [3.0.5-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.5-unstable.1...aws-amplify-angular@3.0.5-unstable.2) (2019-07-09) **Note:** Version bump only for package aws-amplify-angular -## [3.0.5-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.5-unstable.0...aws-amplify-angular@3.0.5-unstable.1) (2019-06-27) - - +## [3.0.5-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.5-unstable.0...aws-amplify-angular@3.0.5-unstable.1) (2019-06-27) **Note:** Version bump only for package aws-amplify-angular -## [3.0.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.4...aws-amplify-angular@3.0.5-unstable.0) (2019-06-18) - - +## [3.0.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.4...aws-amplify-angular@3.0.5-unstable.0) (2019-06-18) **Note:** Version bump only for package aws-amplify-angular -## [3.0.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.4-unstable.3...aws-amplify-angular@3.0.4) (2019-06-17) - - +## [3.0.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.4-unstable.3...aws-amplify-angular@3.0.4) (2019-06-17) **Note:** Version bump only for package aws-amplify-angular -## [3.0.4-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.4-unstable.2...aws-amplify-angular@3.0.4-unstable.3) (2019-06-06) - - +## [3.0.4-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.4-unstable.2...aws-amplify-angular@3.0.4-unstable.3) (2019-06-06) **Note:** Version bump only for package aws-amplify-angular -## [3.0.4-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.4-unstable.1...aws-amplify-angular@3.0.4-unstable.2) (2019-06-03) - - +## [3.0.4-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.4-unstable.1...aws-amplify-angular@3.0.4-unstable.2) (2019-06-03) **Note:** Version bump only for package aws-amplify-angular -## [3.0.4-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3...aws-amplify-angular@3.0.4-unstable.1) (2019-05-24) +## [3.0.4-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3...aws-amplify-angular@3.0.4-unstable.1) (2019-05-24) ### Bug Fixes -* **aws-amplify:** manual version bumps for lerna issue ([9ce5a72](https://github.com/aws-amplify/amplify-js/commit/9ce5a72)) - - - +- **aws-amplify:** manual version bumps for lerna issue ([9ce5a72](https://github.com/aws-amplify/amplify-js/commit/9ce5a72)) -## [3.0.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3-unstable.4...aws-amplify-angular@3.0.3) (2019-05-14) - - +## [3.0.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3-unstable.4...aws-amplify-angular@3.0.3) (2019-05-14) **Note:** Version bump only for package aws-amplify-angular -## [3.0.3-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3-unstable.3...aws-amplify-angular@3.0.3-unstable.4) (2019-05-14) - - +## [3.0.3-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3-unstable.3...aws-amplify-angular@3.0.3-unstable.4) (2019-05-14) **Note:** Version bump only for package aws-amplify-angular -## [3.0.3-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3-unstable.2...aws-amplify-angular@3.0.3-unstable.3) (2019-05-13) +## [3.0.3-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3-unstable.2...aws-amplify-angular@3.0.3-unstable.3) (2019-05-13) ### Bug Fixes -* add a todo to the greeting object in order to adjust the Angular Greeting Component to match React, fix typo in requireNewPassword ([49eae14](https://github.com/aws-amplify/amplify-js/commit/49eae14)) - - - +- add a todo to the greeting object in order to adjust the Angular Greeting Component to match React, fix typo in requireNewPassword ([49eae14](https://github.com/aws-amplify/amplify-js/commit/49eae14)) -## [3.0.3-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3-unstable.1...aws-amplify-angular@3.0.3-unstable.2) (2019-05-13) - - +## [3.0.3-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3-unstable.1...aws-amplify-angular@3.0.3-unstable.2) (2019-05-13) **Note:** Version bump only for package aws-amplify-angular -## [3.0.3-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3-unstable.0...aws-amplify-angular@3.0.3-unstable.1) (2019-05-10) - - +## [3.0.3-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.3-unstable.0...aws-amplify-angular@3.0.3-unstable.1) (2019-05-10) **Note:** Version bump only for package aws-amplify-angular -## [3.0.3-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2...aws-amplify-angular@3.0.3-unstable.0) (2019-05-09) - - +## [3.0.3-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2...aws-amplify-angular@3.0.3-unstable.0) (2019-05-09) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.15...aws-amplify-angular@3.0.2) (2019-05-06) - - +## [3.0.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.15...aws-amplify-angular@3.0.2) (2019-05-06) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.15](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.14...aws-amplify-angular@3.0.2-unstable.15) (2019-05-06) - - +## [3.0.2-unstable.15](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.14...aws-amplify-angular@3.0.2-unstable.15) (2019-05-06) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.14](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.13...aws-amplify-angular@3.0.2-unstable.14) (2019-05-06) - - +## [3.0.2-unstable.14](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.13...aws-amplify-angular@3.0.2-unstable.14) (2019-05-06) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.12...aws-amplify-angular@3.0.2-unstable.13) (2019-05-03) - - +## [3.0.2-unstable.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.12...aws-amplify-angular@3.0.2-unstable.13) (2019-05-03) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.11...aws-amplify-angular@3.0.2-unstable.12) (2019-04-26) - - +## [3.0.2-unstable.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.11...aws-amplify-angular@3.0.2-unstable.12) (2019-04-26) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.10...aws-amplify-angular@3.0.2-unstable.11) (2019-04-26) - - +## [3.0.2-unstable.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.10...aws-amplify-angular@3.0.2-unstable.11) (2019-04-26) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.9...aws-amplify-angular@3.0.2-unstable.10) (2019-04-24) - - +## [3.0.2-unstable.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.9...aws-amplify-angular@3.0.2-unstable.10) (2019-04-24) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.8...aws-amplify-angular@3.0.2-unstable.9) (2019-04-24) - - +## [3.0.2-unstable.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.8...aws-amplify-angular@3.0.2-unstable.9) (2019-04-24) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.7...aws-amplify-angular@3.0.2-unstable.8) (2019-04-22) - - +## [3.0.2-unstable.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.7...aws-amplify-angular@3.0.2-unstable.8) (2019-04-22) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.6...aws-amplify-angular@3.0.2-unstable.7) (2019-04-19) - - +## [3.0.2-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.6...aws-amplify-angular@3.0.2-unstable.7) (2019-04-19) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.5...aws-amplify-angular@3.0.2-unstable.6) (2019-04-17) - - +## [3.0.2-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.5...aws-amplify-angular@3.0.2-unstable.6) (2019-04-17) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.4...aws-amplify-angular@3.0.2-unstable.5) (2019-04-16) - - +## [3.0.2-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.4...aws-amplify-angular@3.0.2-unstable.5) (2019-04-16) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.3...aws-amplify-angular@3.0.2-unstable.4) (2019-04-16) +## [3.0.2-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.3...aws-amplify-angular@3.0.2-unstable.4) (2019-04-16) ### Bug Fixes -* **aws-amplify-angular:** clears error message on state change ([b19de01](https://github.com/aws-amplify/amplify-js/commit/b19de01)) - - - +- **aws-amplify-angular:** clears error message on state change ([b19de01](https://github.com/aws-amplify/amplify-js/commit/b19de01)) -## [3.0.2-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.2...aws-amplify-angular@3.0.2-unstable.3) (2019-04-15) +## [3.0.2-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.2...aws-amplify-angular@3.0.2-unstable.3) (2019-04-15) ### Bug Fixes -* **aws-amplify-angular:** moves rxjs-compat to dependencies ([83e1cc2](https://github.com/aws-amplify/amplify-js/commit/83e1cc2)) - - - +- **aws-amplify-angular:** moves rxjs-compat to dependencies ([83e1cc2](https://github.com/aws-amplify/amplify-js/commit/83e1cc2)) -## [3.0.2-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.1...aws-amplify-angular@3.0.2-unstable.2) (2019-04-15) - - +## [3.0.2-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.1...aws-amplify-angular@3.0.2-unstable.2) (2019-04-15) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.0...aws-amplify-angular@3.0.2-unstable.1) (2019-04-12) - - +## [3.0.2-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.2-unstable.0...aws-amplify-angular@3.0.2-unstable.1) (2019-04-12) **Note:** Version bump only for package aws-amplify-angular -## [3.0.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.1...aws-amplify-angular@3.0.2-unstable.0) (2019-04-12) - - +## [3.0.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.1...aws-amplify-angular@3.0.2-unstable.0) (2019-04-12) **Note:** Version bump only for package aws-amplify-angular -## [3.0.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.0...aws-amplify-angular@3.0.1) (2019-04-11) +## [3.0.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.0...aws-amplify-angular@3.0.1) (2019-04-11) ### Bug Fixes -* **aws-amplify-angular:** preparing release ([84f261a](https://github.com/aws-amplify/amplify-js/commit/84f261a)) - - - +- **aws-amplify-angular:** preparing release ([84f261a](https://github.com/aws-amplify/amplify-js/commit/84f261a)) -# [3.0.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.0-unstable.2...aws-amplify-angular@3.0.0) (2019-04-11) - - +# [3.0.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.0-unstable.2...aws-amplify-angular@3.0.0) (2019-04-11) **Note:** Version bump only for package aws-amplify-angular -# [3.0.0-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.0-unstable.1...aws-amplify-angular@3.0.0-unstable.2) (2019-04-10) - - +# [3.0.0-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@3.0.0-unstable.1...aws-amplify-angular@3.0.0-unstable.2) (2019-04-10) **Note:** Version bump only for package aws-amplify-angular -# [3.0.0-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.13-unstable.0...aws-amplify-angular@3.0.0-unstable.1) (2019-04-09) - - +# [3.0.0-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.13-unstable.0...aws-amplify-angular@3.0.0-unstable.1) (2019-04-09) **Note:** Version bump only for package aws-amplify-angular -## [2.1.13-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.12...aws-amplify-angular@2.1.13-unstable.0) (2019-04-09) - - +## [2.1.13-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.12...aws-amplify-angular@2.1.13-unstable.0) (2019-04-09) **Note:** Version bump only for package aws-amplify-angular -## [2.1.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.12-unstable.3...aws-amplify-angular@2.1.12) (2019-04-09) - - +## [2.1.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.12-unstable.3...aws-amplify-angular@2.1.12) (2019-04-09) **Note:** Version bump only for package aws-amplify-angular -## [2.1.12-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.12-unstable.2...aws-amplify-angular@2.1.12-unstable.3) (2019-04-08) - - +## [2.1.12-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.12-unstable.2...aws-amplify-angular@2.1.12-unstable.3) (2019-04-08) **Note:** Version bump only for package aws-amplify-angular -## [2.1.12-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.12-unstable.1...aws-amplify-angular@2.1.12-unstable.2) (2019-04-08) - - +## [2.1.12-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.12-unstable.1...aws-amplify-angular@2.1.12-unstable.2) (2019-04-08) **Note:** Version bump only for package aws-amplify-angular -## [2.1.12-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.12-unstable.0...aws-amplify-angular@2.1.12-unstable.1) (2019-04-07) - - +## [2.1.12-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.12-unstable.0...aws-amplify-angular@2.1.12-unstable.1) (2019-04-07) **Note:** Version bump only for package aws-amplify-angular -## [2.1.12-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.11...aws-amplify-angular@2.1.12-unstable.0) (2019-04-05) - - +## [2.1.12-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.11...aws-amplify-angular@2.1.12-unstable.0) (2019-04-05) **Note:** Version bump only for package aws-amplify-angular -## [2.1.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.11-unstable.1...aws-amplify-angular@2.1.11) (2019-04-04) - - +## [2.1.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.11-unstable.1...aws-amplify-angular@2.1.11) (2019-04-04) **Note:** Version bump only for package aws-amplify-angular -## [2.1.11-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.11-unstable.0...aws-amplify-angular@2.1.11-unstable.1) (2019-04-04) - - +## [2.1.11-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.11-unstable.0...aws-amplify-angular@2.1.11-unstable.1) (2019-04-04) **Note:** Version bump only for package aws-amplify-angular -## [2.1.11-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10...aws-amplify-angular@2.1.11-unstable.0) (2019-04-02) - - +## [2.1.11-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10...aws-amplify-angular@2.1.11-unstable.0) (2019-04-02) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.12...aws-amplify-angular@2.1.10) (2019-03-28) - - +## [2.1.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.12...aws-amplify-angular@2.1.10) (2019-03-28) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.11...aws-amplify-angular@2.1.10-unstable.12) (2019-03-28) - - +## [2.1.10-unstable.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.11...aws-amplify-angular@2.1.10-unstable.12) (2019-03-28) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.10...aws-amplify-angular@2.1.10-unstable.11) (2019-03-25) - - +## [2.1.10-unstable.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.10...aws-amplify-angular@2.1.10-unstable.11) (2019-03-25) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.9...aws-amplify-angular@2.1.10-unstable.10) (2019-03-24) - - +## [2.1.10-unstable.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.9...aws-amplify-angular@2.1.10-unstable.10) (2019-03-24) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.8...aws-amplify-angular@2.1.10-unstable.9) (2019-03-22) - - +## [2.1.10-unstable.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.8...aws-amplify-angular@2.1.10-unstable.9) (2019-03-22) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.7...aws-amplify-angular@2.1.10-unstable.8) (2019-03-22) - - +## [2.1.10-unstable.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.7...aws-amplify-angular@2.1.10-unstable.8) (2019-03-22) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.6...aws-amplify-angular@2.1.10-unstable.7) (2019-03-21) - - +## [2.1.10-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.6...aws-amplify-angular@2.1.10-unstable.7) (2019-03-21) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.5...aws-amplify-angular@2.1.10-unstable.6) (2019-03-20) - - +## [2.1.10-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.5...aws-amplify-angular@2.1.10-unstable.6) (2019-03-20) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.4...aws-amplify-angular@2.1.10-unstable.5) (2019-03-19) - - +## [2.1.10-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.4...aws-amplify-angular@2.1.10-unstable.5) (2019-03-19) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.3...aws-amplify-angular@2.1.10-unstable.4) (2019-03-18) - - +## [2.1.10-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.3...aws-amplify-angular@2.1.10-unstable.4) (2019-03-18) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.2...aws-amplify-angular@2.1.10-unstable.3) (2019-03-08) - - +## [2.1.10-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.2...aws-amplify-angular@2.1.10-unstable.3) (2019-03-08) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.1...aws-amplify-angular@2.1.10-unstable.2) (2019-03-07) - - +## [2.1.10-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.1...aws-amplify-angular@2.1.10-unstable.2) (2019-03-07) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.0...aws-amplify-angular@2.1.10-unstable.1) (2019-03-07) - - +## [2.1.10-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.10-unstable.0...aws-amplify-angular@2.1.10-unstable.1) (2019-03-07) **Note:** Version bump only for package aws-amplify-angular -## [2.1.10-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.9...aws-amplify-angular@2.1.10-unstable.0) (2019-03-06) - - +## [2.1.10-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.9...aws-amplify-angular@2.1.10-unstable.0) (2019-03-06) **Note:** Version bump only for package aws-amplify-angular -## [2.1.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.9-unstable.3...aws-amplify-angular@2.1.9) (2019-03-06) - - +## [2.1.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.9-unstable.3...aws-amplify-angular@2.1.9) (2019-03-06) **Note:** Version bump only for package aws-amplify-angular -## [2.1.9-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.9-unstable.2...aws-amplify-angular@2.1.9-unstable.3) (2019-03-06) - - +## [2.1.9-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.9-unstable.2...aws-amplify-angular@2.1.9-unstable.3) (2019-03-06) **Note:** Version bump only for package aws-amplify-angular -## [2.1.9-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.9-unstable.1...aws-amplify-angular@2.1.9-unstable.2) (2019-03-05) - - +## [2.1.9-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.9-unstable.1...aws-amplify-angular@2.1.9-unstable.2) (2019-03-05) **Note:** Version bump only for package aws-amplify-angular -## [2.1.9-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.9-unstable.0...aws-amplify-angular@2.1.9-unstable.1) (2019-03-04) - - +## [2.1.9-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.9-unstable.0...aws-amplify-angular@2.1.9-unstable.1) (2019-03-04) **Note:** Version bump only for package aws-amplify-angular -## [2.1.9-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.8...aws-amplify-angular@2.1.9-unstable.0) (2019-03-04) - - +## [2.1.9-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.8...aws-amplify-angular@2.1.9-unstable.0) (2019-03-04) **Note:** Version bump only for package aws-amplify-angular -## [2.1.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7...aws-amplify-angular@2.1.8) (2019-03-04) - - +## [2.1.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7...aws-amplify-angular@2.1.8) (2019-03-04) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.16...aws-amplify-angular@2.1.7) (2019-03-04) - - +## [2.1.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.16...aws-amplify-angular@2.1.7) (2019-03-04) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.16](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.15...aws-amplify-angular@2.1.7-unstable.16) (2019-03-04) - - +## [2.1.7-unstable.16](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.15...aws-amplify-angular@2.1.7-unstable.16) (2019-03-04) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.15](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.14...aws-amplify-angular@2.1.7-unstable.15) (2019-03-04) - - +## [2.1.7-unstable.15](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.14...aws-amplify-angular@2.1.7-unstable.15) (2019-03-04) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.14](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.13...aws-amplify-angular@2.1.7-unstable.14) (2019-03-01) - - +## [2.1.7-unstable.14](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.13...aws-amplify-angular@2.1.7-unstable.14) (2019-03-01) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.12...aws-amplify-angular@2.1.7-unstable.13) (2019-02-28) - - +## [2.1.7-unstable.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.12...aws-amplify-angular@2.1.7-unstable.13) (2019-02-28) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.11...aws-amplify-angular@2.1.7-unstable.12) (2019-02-27) - - +## [2.1.7-unstable.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.11...aws-amplify-angular@2.1.7-unstable.12) (2019-02-27) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.10...aws-amplify-angular@2.1.7-unstable.11) (2019-02-27) - - +## [2.1.7-unstable.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.10...aws-amplify-angular@2.1.7-unstable.11) (2019-02-27) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.9...aws-amplify-angular@2.1.7-unstable.10) (2019-02-27) - - +## [2.1.7-unstable.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.9...aws-amplify-angular@2.1.7-unstable.10) (2019-02-27) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.8...aws-amplify-angular@2.1.7-unstable.9) (2019-02-20) - - +## [2.1.7-unstable.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.8...aws-amplify-angular@2.1.7-unstable.9) (2019-02-20) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.7...aws-amplify-angular@2.1.7-unstable.8) (2019-02-11) - - +## [2.1.7-unstable.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.7...aws-amplify-angular@2.1.7-unstable.8) (2019-02-11) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.6...aws-amplify-angular@2.1.7-unstable.7) (2019-01-22) - - +## [2.1.7-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.6...aws-amplify-angular@2.1.7-unstable.7) (2019-01-22) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.5...aws-amplify-angular@2.1.7-unstable.6) (2019-01-21) - - +## [2.1.7-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.5...aws-amplify-angular@2.1.7-unstable.6) (2019-01-21) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.4...aws-amplify-angular@2.1.7-unstable.5) (2019-01-21) - - +## [2.1.7-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.4...aws-amplify-angular@2.1.7-unstable.5) (2019-01-21) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.3...aws-amplify-angular@2.1.7-unstable.4) (2019-01-18) - - +## [2.1.7-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.3...aws-amplify-angular@2.1.7-unstable.4) (2019-01-18) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.2...aws-amplify-angular@2.1.7-unstable.3) (2019-01-17) +## [2.1.7-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.2...aws-amplify-angular@2.1.7-unstable.3) (2019-01-17) ### Bug Fixes -* **@aws-amplify/aws-amplify-angular:** added labels for inputs in the forgot password component. ([38d44be](https://github.com/aws-amplify/amplify-js/commit/38d44be)) - - - +- **@aws-amplify/aws-amplify-angular:** added labels for inputs in the forgot password component. ([38d44be](https://github.com/aws-amplify/amplify-js/commit/38d44be)) -## [2.1.7-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.1...aws-amplify-angular@2.1.7-unstable.2) (2019-01-10) - - +## [2.1.7-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.1...aws-amplify-angular@2.1.7-unstable.2) (2019-01-10) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.0...aws-amplify-angular@2.1.7-unstable.1) (2019-01-10) - - +## [2.1.7-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.7-unstable.0...aws-amplify-angular@2.1.7-unstable.1) (2019-01-10) **Note:** Version bump only for package aws-amplify-angular -## [2.1.7-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.6...aws-amplify-angular@2.1.7-unstable.0) (2019-01-10) - - +## [2.1.7-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.6...aws-amplify-angular@2.1.7-unstable.0) (2019-01-10) **Note:** Version bump only for package aws-amplify-angular -## [2.1.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.6-unstable.1...aws-amplify-angular@2.1.6) (2019-01-10) - - +## [2.1.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.6-unstable.1...aws-amplify-angular@2.1.6) (2019-01-10) **Note:** Version bump only for package aws-amplify-angular -## [2.1.6-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.6-unstable.0...aws-amplify-angular@2.1.6-unstable.1) (2018-12-26) - - +## [2.1.6-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.6-unstable.0...aws-amplify-angular@2.1.6-unstable.1) (2018-12-26) **Note:** Version bump only for package aws-amplify-angular -## [2.1.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5...aws-amplify-angular@2.1.6-unstable.0) (2018-12-26) - - +## [2.1.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5...aws-amplify-angular@2.1.6-unstable.0) (2018-12-26) **Note:** Version bump only for package aws-amplify-angular -## [2.1.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.7...aws-amplify-angular@2.1.5) (2018-12-26) - - +## [2.1.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.7...aws-amplify-angular@2.1.5) (2018-12-26) **Note:** Version bump only for package aws-amplify-angular -## [2.1.5-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.6...aws-amplify-angular@2.1.5-unstable.7) (2018-12-24) - - +## [2.1.5-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.6...aws-amplify-angular@2.1.5-unstable.7) (2018-12-24) **Note:** Version bump only for package aws-amplify-angular -## [2.1.5-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.5...aws-amplify-angular@2.1.5-unstable.6) (2018-12-24) - - +## [2.1.5-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.5...aws-amplify-angular@2.1.5-unstable.6) (2018-12-24) **Note:** Version bump only for package aws-amplify-angular -## [2.1.5-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.4...aws-amplify-angular@2.1.5-unstable.5) (2018-12-24) - - +## [2.1.5-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.4...aws-amplify-angular@2.1.5-unstable.5) (2018-12-24) **Note:** Version bump only for package aws-amplify-angular -## [2.1.5-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.3...aws-amplify-angular@2.1.5-unstable.4) (2018-12-22) - - +## [2.1.5-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.3...aws-amplify-angular@2.1.5-unstable.4) (2018-12-22) **Note:** Version bump only for package aws-amplify-angular -## [2.1.5-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.2...aws-amplify-angular@2.1.5-unstable.3) (2018-12-20) - - +## [2.1.5-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.2...aws-amplify-angular@2.1.5-unstable.3) (2018-12-20) **Note:** Version bump only for package aws-amplify-angular -## [2.1.5-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.1...aws-amplify-angular@2.1.5-unstable.2) (2018-12-19) - - +## [2.1.5-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.1...aws-amplify-angular@2.1.5-unstable.2) (2018-12-19) **Note:** Version bump only for package aws-amplify-angular -## [2.1.5-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.0...aws-amplify-angular@2.1.5-unstable.1) (2018-12-19) - - +## [2.1.5-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.5-unstable.0...aws-amplify-angular@2.1.5-unstable.1) (2018-12-19) **Note:** Version bump only for package aws-amplify-angular -## [2.1.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.4...aws-amplify-angular@2.1.5-unstable.0) (2018-12-17) - - +## [2.1.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.4...aws-amplify-angular@2.1.5-unstable.0) (2018-12-17) -**Note:** Version bump only for package aws-amplify-angular - - -## [2.1.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.3-unstable.1...aws-amplify-angular@2.1.4) (2018-12-15) - +**Note:** Version bump only for package aws-amplify-angular + +## [2.1.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.3-unstable.1...aws-amplify-angular@2.1.4) (2018-12-15) **Note:** Version bump only for package aws-amplify-angular + ## [2.1.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.2...aws-amplify-angular@2.1.3) (2018-12-14) -## [2.1.3-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.3-unstable.0...aws-amplify-angular@2.1.3-unstable.1) (2018-12-14) - - +## [2.1.3-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.3-unstable.0...aws-amplify-angular@2.1.3-unstable.1) (2018-12-14) **Note:** Version bump only for package aws-amplify-angular - -## [2.1.3-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.2...aws-amplify-angular@2.1.3-unstable.0) (2018-12-14) - - - +## [2.1.3-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.2...aws-amplify-angular@2.1.3-unstable.0) (2018-12-14) **Note:** Version bump only for package aws-amplify-angular -## [2.1.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.2-unstable.0...aws-amplify-angular@2.1.2) (2018-12-14) - - +## [2.1.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.2-unstable.0...aws-amplify-angular@2.1.2) (2018-12-14) **Note:** Version bump only for package aws-amplify-angular -## [2.1.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1...aws-amplify-angular@2.1.2-unstable.0) (2018-12-13) +## [2.1.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1...aws-amplify-angular@2.1.2-unstable.0) (2018-12-13) ### Features -* **@aws-amplify/interactions @aws-amplify/react @aws-amplify/react-native @aws-amplify/angular @aws-amplify/vue:** Update interactions to include voice ([#2121](https://github.com/aws-amplify/amplify-js/issues/2121)) ([938d2a5](https://github.com/aws-amplify/amplify-js/commit/938d2a5)) - - - +- **@aws-amplify/interactions @aws-amplify/react @aws-amplify/react-native @aws-amplify/angular @aws-amplify/vue:** Update interactions to include voice ([#2121](https://github.com/aws-amplify/amplify-js/issues/2121)) ([938d2a5](https://github.com/aws-amplify/amplify-js/commit/938d2a5)) -## [2.1.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.7...aws-amplify-angular@2.1.1) (2018-12-13) - - +## [2.1.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.7...aws-amplify-angular@2.1.1) (2018-12-13) **Note:** Version bump only for package aws-amplify-angular -## [2.1.1-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.6...aws-amplify-angular@2.1.1-unstable.7) (2018-12-13) - - +## [2.1.1-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.6...aws-amplify-angular@2.1.1-unstable.7) (2018-12-13) **Note:** Version bump only for package aws-amplify-angular -## [2.1.1-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.5...aws-amplify-angular@2.1.1-unstable.6) (2018-12-13) - - +## [2.1.1-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.5...aws-amplify-angular@2.1.1-unstable.6) (2018-12-13) **Note:** Version bump only for package aws-amplify-angular -## [2.1.1-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.4...aws-amplify-angular@2.1.1-unstable.5) (2018-12-13) - - +## [2.1.1-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.4...aws-amplify-angular@2.1.1-unstable.5) (2018-12-13) **Note:** Version bump only for package aws-amplify-angular -## [2.1.1-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.3...aws-amplify-angular@2.1.1-unstable.4) (2018-12-13) - - +## [2.1.1-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.3...aws-amplify-angular@2.1.1-unstable.4) (2018-12-13) **Note:** Version bump only for package aws-amplify-angular -## [2.1.1-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.2...aws-amplify-angular@2.1.1-unstable.3) (2018-12-12) - - +## [2.1.1-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.2...aws-amplify-angular@2.1.1-unstable.3) (2018-12-12) **Note:** Version bump only for package aws-amplify-angular -## [2.1.1-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.1...aws-amplify-angular@2.1.1-unstable.2) (2018-12-10) - - +## [2.1.1-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.1...aws-amplify-angular@2.1.1-unstable.2) (2018-12-10) **Note:** Version bump only for package aws-amplify-angular -## [2.1.1-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.0...aws-amplify-angular@2.1.1-unstable.1) (2018-12-10) - - +## [2.1.1-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-unstable.0...aws-amplify-angular@2.1.1-unstable.1) (2018-12-10) **Note:** Version bump only for package aws-amplify-angular -## [2.1.1-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.17-unstable.1...aws-amplify-angular@2.1.1-unstable.0) (2018-12-10) - - +## [2.1.1-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.17-unstable.1...aws-amplify-angular@2.1.1-unstable.0) (2018-12-10) **Note:** Version bump only for package aws-amplify-angular -## [2.0.17-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.17-unstable.0...aws-amplify-angular@2.0.17-unstable.1) (2018-12-07) - - +## [2.0.17-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.17-unstable.0...aws-amplify-angular@2.0.17-unstable.1) (2018-12-07) **Note:** Version bump only for package aws-amplify-angular -## [2.0.17-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.16...aws-amplify-angular@2.0.17-unstable.0) (2018-12-07) - - +## [2.0.17-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.16...aws-amplify-angular@2.0.17-unstable.0) (2018-12-07) **Note:** Version bump only for package aws-amplify-angular -## [2.0.16](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.15...aws-amplify-angular@2.0.16) (2018-12-07) - - +## [2.0.16](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.15...aws-amplify-angular@2.0.16) (2018-12-07) **Note:** Version bump only for package aws-amplify-angular -## [2.0.16-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.16-unstable.0...aws-amplify-angular@2.0.16-unstable.1) (2018-12-07) - - +## [2.0.16-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.16-unstable.0...aws-amplify-angular@2.0.16-unstable.1) (2018-12-07) **Note:** Version bump only for package aws-amplify-angular -## [2.0.16-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.15...aws-amplify-angular@2.0.16-unstable.0) (2018-12-06) - - +## [2.0.16-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.15...aws-amplify-angular@2.0.16-unstable.0) (2018-12-06) **Note:** Version bump only for package aws-amplify-angular -## [2.0.15](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14...aws-amplify-angular@2.0.15) (2018-12-06) - - +## [2.0.15](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14...aws-amplify-angular@2.0.15) (2018-12-06) **Note:** Version bump only for package aws-amplify-angular -## [2.0.15-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14...aws-amplify-angular@2.0.15-unstable.0) (2018-12-05) - - +## [2.0.15-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14...aws-amplify-angular@2.0.15-unstable.0) (2018-12-05) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.17...aws-amplify-angular@2.0.14) (2018-12-03) - - +## [2.0.14](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.17...aws-amplify-angular@2.0.14) (2018-12-03) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.17](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.16...aws-amplify-angular@2.0.14-unstable.17) (2018-12-03) - - +## [2.0.14-unstable.17](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.16...aws-amplify-angular@2.0.14-unstable.17) (2018-12-03) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.16](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.15...aws-amplify-angular@2.0.14-unstable.16) (2018-12-03) - - +## [2.0.14-unstable.16](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.15...aws-amplify-angular@2.0.14-unstable.16) (2018-12-03) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.15](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.14...aws-amplify-angular@2.0.14-unstable.15) (2018-11-30) - - - +## [2.0.14-unstable.15](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.14...aws-amplify-angular@2.0.14-unstable.15) (2018-11-30) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.14](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.13...aws-amplify-angular@2.0.14-unstable.14) (2018-11-29) - - +## [2.0.14-unstable.14](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.13...aws-amplify-angular@2.0.14-unstable.14) (2018-11-29) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.12...aws-amplify-angular@2.0.14-unstable.13) (2018-11-29) - - +## [2.0.14-unstable.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.12...aws-amplify-angular@2.0.14-unstable.13) (2018-11-29) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.11...aws-amplify-angular@2.0.14-unstable.12) (2018-11-27) - - +## [2.0.14-unstable.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.11...aws-amplify-angular@2.0.14-unstable.12) (2018-11-27) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.10...aws-amplify-angular@2.0.14-unstable.11) (2018-11-26) - - +## [2.0.14-unstable.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.10...aws-amplify-angular@2.0.14-unstable.11) (2018-11-26) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.9...aws-amplify-angular@2.0.14-unstable.10) (2018-11-23) - - +## [2.0.14-unstable.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.9...aws-amplify-angular@2.0.14-unstable.10) (2018-11-23) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.8...aws-amplify-angular@2.0.14-unstable.9) (2018-11-21) - - +## [2.0.14-unstable.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.8...aws-amplify-angular@2.0.14-unstable.9) (2018-11-21) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.7...aws-amplify-angular@2.0.14-unstable.8) (2018-11-20) +## [2.0.14-unstable.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.7...aws-amplify-angular@2.0.14-unstable.8) (2018-11-20) **Note:** Version bump only for package aws-amplify-angular - -## [2.1.1-beta.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-beta.1...aws-amplify-angular@2.1.1-beta.2) (2018-11-19) +## [2.1.1-beta.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.1.1-beta.1...aws-amplify-angular@2.1.1-beta.2) (2018-11-19) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.6...aws-amplify-angular@2.0.14-unstable.7) (2018-11-19) - - +## [2.0.14-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.6...aws-amplify-angular@2.0.14-unstable.7) (2018-11-19) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.5...aws-amplify-angular@2.0.14-unstable.6) (2018-11-19) - - +## [2.0.14-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.5...aws-amplify-angular@2.0.14-unstable.6) (2018-11-19) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.4...aws-amplify-angular@2.0.14-unstable.5) (2018-11-19) - - +## [2.0.14-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.4...aws-amplify-angular@2.0.14-unstable.5) (2018-11-19) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.3...aws-amplify-angular@2.0.14-unstable.4) (2018-11-17) - - +## [2.0.14-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.3...aws-amplify-angular@2.0.14-unstable.4) (2018-11-17) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.2...aws-amplify-angular@2.0.14-unstable.3) (2018-11-16) - - +## [2.0.14-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.2...aws-amplify-angular@2.0.14-unstable.3) (2018-11-16) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.1...aws-amplify-angular@2.0.14-unstable.2) (2018-11-16) - - +## [2.0.14-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.1...aws-amplify-angular@2.0.14-unstable.2) (2018-11-16) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.0...aws-amplify-angular@2.0.14-unstable.1) (2018-11-15) +## [2.0.14-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.14-unstable.0...aws-amplify-angular@2.0.14-unstable.1) (2018-11-15) -## [2.1.1-beta.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.6...aws-amplify-angular@2.1.1-beta.1) (2018-11-14) +## [2.1.1-beta.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.6...aws-amplify-angular@2.1.1-beta.1) (2018-11-14) **Note:** Version bump only for package aws-amplify-angular -## [2.0.14-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13...aws-amplify-angular@2.0.14-unstable.0) (2018-11-13) - - +## [2.0.14-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13...aws-amplify-angular@2.0.14-unstable.0) (2018-11-13) **Note:** Version bump only for package aws-amplify-angular -## [2.0.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.6...aws-amplify-angular@2.0.13) (2018-11-12) +## [2.0.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.6...aws-amplify-angular@2.0.13) (2018-11-12) **Note:** Version bump only for package aws-amplify-angular -## [2.0.13-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.5...aws-amplify-angular@2.0.13-unstable.6) (2018-11-12) - - +## [2.0.13-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.5...aws-amplify-angular@2.0.13-unstable.6) (2018-11-12) **Note:** Version bump only for package aws-amplify-angular -## [2.0.13-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.4...aws-amplify-angular@2.0.13-unstable.5) (2018-11-10) - - +## [2.0.13-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.4...aws-amplify-angular@2.0.13-unstable.5) (2018-11-10) **Note:** Version bump only for package aws-amplify-angular -## [2.0.13-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.3...aws-amplify-angular@2.0.13-unstable.4) (2018-11-09) - - +## [2.0.13-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.3...aws-amplify-angular@2.0.13-unstable.4) (2018-11-09) **Note:** Version bump only for package aws-amplify-angular -## [2.0.13-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.2...aws-amplify-angular@2.0.13-unstable.3) (2018-11-09) - - +## [2.0.13-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.2...aws-amplify-angular@2.0.13-unstable.3) (2018-11-09) **Note:** Version bump only for package aws-amplify-angular -## [2.0.13-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.1...aws-amplify-angular@2.0.13-unstable.2) (2018-11-09) - - +## [2.0.13-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.1...aws-amplify-angular@2.0.13-unstable.2) (2018-11-09) **Note:** Version bump only for package aws-amplify-angular -## [2.0.13-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.0...aws-amplify-angular@2.0.13-unstable.1) (2018-11-06) - - +## [2.0.13-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.13-unstable.0...aws-amplify-angular@2.0.13-unstable.1) (2018-11-06) **Note:** Version bump only for package aws-amplify-angular -## [2.0.13-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12...aws-amplify-angular@2.0.13-unstable.0) (2018-11-06) - - +## [2.0.13-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12...aws-amplify-angular@2.0.13-unstable.0) (2018-11-06) **Note:** Version bump only for package aws-amplify-angular -## [2.0.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12-unstable.4...aws-amplify-angular@2.0.12) (2018-11-01) - - +## [2.0.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12-unstable.4...aws-amplify-angular@2.0.12) (2018-11-01) **Note:** Version bump only for package aws-amplify-angular -## [2.0.12-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12-unstable.3...aws-amplify-angular@2.0.12-unstable.4) (2018-11-01) - - +## [2.0.12-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12-unstable.3...aws-amplify-angular@2.0.12-unstable.4) (2018-11-01) **Note:** Version bump only for package aws-amplify-angular -## [2.0.12-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12-unstable.2...aws-amplify-angular@2.0.12-unstable.3) (2018-10-30) - - +## [2.0.12-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12-unstable.2...aws-amplify-angular@2.0.12-unstable.3) (2018-10-30) **Note:** Version bump only for package aws-amplify-angular -## [2.0.12-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12-unstable.1...aws-amplify-angular@2.0.12-unstable.2) (2018-10-30) - - +## [2.0.12-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12-unstable.1...aws-amplify-angular@2.0.12-unstable.2) (2018-10-30) **Note:** Version bump only for package aws-amplify-angular -## [2.0.12-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12-unstable.0...aws-amplify-angular@2.0.12-unstable.1) (2018-10-30) - - +## [2.0.12-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.12-unstable.0...aws-amplify-angular@2.0.12-unstable.1) (2018-10-30) **Note:** Version bump only for package aws-amplify-angular -## [2.0.12-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.11...aws-amplify-angular@2.0.12-unstable.0) (2018-10-30) - - +## [2.0.12-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.11...aws-amplify-angular@2.0.12-unstable.0) (2018-10-30) **Note:** Version bump only for package aws-amplify-angular -## [2.0.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.11-unstable.3...aws-amplify-angular@2.0.11) (2018-10-29) - - +## [2.0.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.11-unstable.3...aws-amplify-angular@2.0.11) (2018-10-29) **Note:** Version bump only for package aws-amplify-angular -## [2.0.11-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.11-unstable.2...aws-amplify-angular@2.0.11-unstable.3) (2018-10-29) - - +## [2.0.11-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.11-unstable.2...aws-amplify-angular@2.0.11-unstable.3) (2018-10-29) **Note:** Version bump only for package aws-amplify-angular -## [2.0.11-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.11-unstable.1...aws-amplify-angular@2.0.11-unstable.2) (2018-10-29) - - +## [2.0.11-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.11-unstable.1...aws-amplify-angular@2.0.11-unstable.2) (2018-10-29) **Note:** Version bump only for package aws-amplify-angular -## [2.0.11-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.11-unstable.0...aws-amplify-angular@2.0.11-unstable.1) (2018-10-18) - - +## [2.0.11-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.11-unstable.0...aws-amplify-angular@2.0.11-unstable.1) (2018-10-18) **Note:** Version bump only for package aws-amplify-angular -## [2.0.11-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10...aws-amplify-angular@2.0.11-unstable.0) (2018-10-18) - - +## [2.0.11-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10...aws-amplify-angular@2.0.11-unstable.0) (2018-10-18) **Note:** Version bump only for package aws-amplify-angular -## [2.0.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10-unstable.4...aws-amplify-angular@2.0.10) (2018-10-17) - - +## [2.0.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10-unstable.4...aws-amplify-angular@2.0.10) (2018-10-17) **Note:** Version bump only for package aws-amplify-angular -## [2.0.10-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10-unstable.3...aws-amplify-angular@2.0.10-unstable.4) (2018-10-17) - - +## [2.0.10-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10-unstable.3...aws-amplify-angular@2.0.10-unstable.4) (2018-10-17) **Note:** Version bump only for package aws-amplify-angular -## [2.0.10-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10-unstable.2...aws-amplify-angular@2.0.10-unstable.3) (2018-10-16) +## [2.0.10-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10-unstable.2...aws-amplify-angular@2.0.10-unstable.3) (2018-10-16) +**Note:** Version bump only for package aws-amplify-angular + -**Note:** Version bump only for package aws-amplify-angular - - -## [2.0.10-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10-unstable.1...aws-amplify-angular@2.0.10-unstable.2) (2018-10-08) - - - +## [2.0.10-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10-unstable.1...aws-amplify-angular@2.0.10-unstable.2) (2018-10-08) **Note:** Version bump only for package aws-amplify-angular -## [2.0.10-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10-unstable.0...aws-amplify-angular@2.0.10-unstable.1) (2018-10-05) - - +## [2.0.10-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.10-unstable.0...aws-amplify-angular@2.0.10-unstable.1) (2018-10-05) **Note:** Version bump only for package aws-amplify-angular -## [2.0.10-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.9-unstable.2...aws-amplify-angular@2.0.10-unstable.0) (2018-10-05) - - +## [2.0.10-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.9-unstable.2...aws-amplify-angular@2.0.10-unstable.0) (2018-10-05) **Note:** Version bump only for package aws-amplify-angular -## [2.0.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.9-unstable.2...aws-amplify-angular@2.0.9) (2018-10-04) - - +## [2.0.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.9-unstable.2...aws-amplify-angular@2.0.9) (2018-10-04) **Note:** Version bump only for package aws-amplify-angular -## [2.0.9-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.9-unstable.1...aws-amplify-angular@2.0.9-unstable.2) (2018-10-03) - - +## [2.0.9-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.9-unstable.1...aws-amplify-angular@2.0.9-unstable.2) (2018-10-03) **Note:** Version bump only for package aws-amplify-angular -## [2.0.9-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.9-unstable.0...aws-amplify-angular@2.0.9-unstable.1) (2018-10-03) - - +## [2.0.9-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.9-unstable.0...aws-amplify-angular@2.0.9-unstable.1) (2018-10-03) **Note:** Version bump only for package aws-amplify-angular -## [2.0.9-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.7...aws-amplify-angular@2.0.9-unstable.0) (2018-10-03) - - +## [2.0.9-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.7...aws-amplify-angular@2.0.9-unstable.0) (2018-10-03) **Note:** Version bump only for package aws-amplify-angular -## [2.0.8](https://github.com/powerful23/aws-amplify/compare/aws-amplify-angular@2.0.8-unstable.7...aws-amplify-angular@2.0.8) (2018-10-03) - - +## [2.0.8](https://github.com/powerful23/aws-amplify/compare/aws-amplify-angular@2.0.8-unstable.7...aws-amplify-angular@2.0.8) (2018-10-03) **Note:** Version bump only for package aws-amplify-angular -## [2.0.8-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.6...aws-amplify-angular@2.0.8-unstable.7) (2018-10-02) - - +## [2.0.8-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.6...aws-amplify-angular@2.0.8-unstable.7) (2018-10-02) **Note:** Version bump only for package aws-amplify-angular -## [2.0.8-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.5...aws-amplify-angular@2.0.8-unstable.6) (2018-10-01) - - +## [2.0.8-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.5...aws-amplify-angular@2.0.8-unstable.6) (2018-10-01) **Note:** Version bump only for package aws-amplify-angular -## [2.0.8-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.4...aws-amplify-angular@2.0.8-unstable.5) (2018-10-01) - - +## [2.0.8-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.4...aws-amplify-angular@2.0.8-unstable.5) (2018-10-01) **Note:** Version bump only for package aws-amplify-angular -## [2.0.8-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.3...aws-amplify-angular@2.0.8-unstable.4) (2018-10-01) - - +## [2.0.8-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.3...aws-amplify-angular@2.0.8-unstable.4) (2018-10-01) **Note:** Version bump only for package aws-amplify-angular -## [2.0.8-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.2...aws-amplify-angular@2.0.8-unstable.3) (2018-09-28) - - +## [2.0.8-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.2...aws-amplify-angular@2.0.8-unstable.3) (2018-09-28) **Note:** Version bump only for package aws-amplify-angular -## [2.0.8-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.1...aws-amplify-angular@2.0.8-unstable.2) (2018-09-27) - - +## [2.0.8-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.1...aws-amplify-angular@2.0.8-unstable.2) (2018-09-27) **Note:** Version bump only for package aws-amplify-angular -## [2.0.8-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.0...aws-amplify-angular@2.0.8-unstable.1) (2018-09-27) - - +## [2.0.8-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.8-unstable.0...aws-amplify-angular@2.0.8-unstable.1) (2018-09-27) **Note:** Version bump only for package aws-amplify-angular -## [2.0.8-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7...aws-amplify-angular@2.0.8-unstable.0) (2018-09-27) - - +## [2.0.8-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7...aws-amplify-angular@2.0.8-unstable.0) (2018-09-27) **Note:** Version bump only for package aws-amplify-angular -## [2.0.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.9...aws-amplify-angular@2.0.7) (2018-09-27) - - +## [2.0.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.9...aws-amplify-angular@2.0.7) (2018-09-27) **Note:** Version bump only for package aws-amplify-angular -## [2.0.7-unstable.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.8...aws-amplify-angular@2.0.7-unstable.9) (2018-09-26) - - +## [2.0.7-unstable.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.8...aws-amplify-angular@2.0.7-unstable.9) (2018-09-26) **Note:** Version bump only for package aws-amplify-angular -## [2.0.7-unstable.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.7...aws-amplify-angular@2.0.7-unstable.8) (2018-09-26) - - +## [2.0.7-unstable.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.7...aws-amplify-angular@2.0.7-unstable.8) (2018-09-26) **Note:** Version bump only for package aws-amplify-angular -## [2.0.7-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.6...aws-amplify-angular@2.0.7-unstable.7) (2018-09-26) - - +## [2.0.7-unstable.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.6...aws-amplify-angular@2.0.7-unstable.7) (2018-09-26) **Note:** Version bump only for package aws-amplify-angular -## [2.0.7-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.4...aws-amplify-angular@2.0.7-unstable.6) (2018-09-26) - - +## [2.0.7-unstable.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.4...aws-amplify-angular@2.0.7-unstable.6) (2018-09-26) **Note:** Version bump only for package aws-amplify-angular -## [2.0.7-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.4...aws-amplify-angular@2.0.7-unstable.5) (2018-09-25) - - +## [2.0.7-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.4...aws-amplify-angular@2.0.7-unstable.5) (2018-09-25) **Note:** Version bump only for package aws-amplify-angular -## [2.0.7-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.3...aws-amplify-angular@2.0.7-unstable.4) (2018-09-25) - - +## [2.0.7-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.3...aws-amplify-angular@2.0.7-unstable.4) (2018-09-25) **Note:** Version bump only for package aws-amplify-angular -## [2.0.7-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.2...aws-amplify-angular@2.0.7-unstable.3) (2018-09-24) - - +## [2.0.7-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.2...aws-amplify-angular@2.0.7-unstable.3) (2018-09-24) **Note:** Version bump only for package aws-amplify-angular -## [2.0.7-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.1...aws-amplify-angular@2.0.7-unstable.2) (2018-09-22) - - +## [2.0.7-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.1...aws-amplify-angular@2.0.7-unstable.2) (2018-09-22) **Note:** Version bump only for package aws-amplify-angular -## [2.0.7-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.0...aws-amplify-angular@2.0.7-unstable.1) (2018-09-22) - - +## [2.0.7-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.7-unstable.0...aws-amplify-angular@2.0.7-unstable.1) (2018-09-22) **Note:** Version bump only for package aws-amplify-angular -## [2.0.7-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.6...aws-amplify-angular@2.0.7-unstable.0) (2018-09-22) - - +## [2.0.7-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.6...aws-amplify-angular@2.0.7-unstable.0) (2018-09-22) **Note:** Version bump only for package aws-amplify-angular -## [2.0.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.6-unstable.0...aws-amplify-angular@2.0.6) (2018-09-21) - - +## [2.0.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.6-unstable.0...aws-amplify-angular@2.0.6) (2018-09-21) **Note:** Version bump only for package aws-amplify-angular -## [2.0.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.5-unstable.3...aws-amplify-angular@2.0.6-unstable.0) (2018-09-21) +## [2.0.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.5-unstable.3...aws-amplify-angular@2.0.6-unstable.0) (2018-09-21) ### Bug Fixes -* bumping version for deploying on unstable tag ([#1706](https://github.com/aws-amplify/amplify-js/issues/1706)) ([b5d6468](https://github.com/aws-amplify/amplify-js/commit/b5d6468)) - - - +- bumping version for deploying on unstable tag ([#1706](https://github.com/aws-amplify/amplify-js/issues/1706)) ([b5d6468](https://github.com/aws-amplify/amplify-js/commit/b5d6468)) -## [2.0.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.4...aws-amplify-angular@2.0.5) (2018-09-21) - - +## [2.0.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.4...aws-amplify-angular@2.0.5) (2018-09-21) **Note:** Version bump only for package aws-amplify-angular -## [2.0.5-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.5-unstable.2...aws-amplify-angular@2.0.5-unstable.3) (2018-09-20) - - +## [2.0.5-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.5-unstable.2...aws-amplify-angular@2.0.5-unstable.3) (2018-09-20) **Note:** Version bump only for package aws-amplify-angular -## [2.0.5-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.5-unstable.1...aws-amplify-angular@2.0.5-unstable.2) (2018-09-20) - - +## [2.0.5-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.5-unstable.1...aws-amplify-angular@2.0.5-unstable.2) (2018-09-20) **Note:** Version bump only for package aws-amplify-angular -## [2.0.5-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.5-unstable.0...aws-amplify-angular@2.0.5-unstable.1) (2018-09-17) - - +## [2.0.5-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.5-unstable.0...aws-amplify-angular@2.0.5-unstable.1) (2018-09-17) **Note:** Version bump only for package aws-amplify-angular -## [2.0.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.4...aws-amplify-angular@2.0.5-unstable.0) (2018-09-17) - - +## [2.0.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.4...aws-amplify-angular@2.0.5-unstable.0) (2018-09-17) **Note:** Version bump only for package aws-amplify-angular -## [2.0.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.3...aws-amplify-angular@2.0.4) (2018-09-17) +## [2.0.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.3...aws-amplify-angular@2.0.4) (2018-09-17) ### Bug Fixes -* **aws-amplify-angular:** authState visibility issues on initial load ([#1657](https://github.com/aws-amplify/amplify-js/issues/1657)) ([50611fe](https://github.com/aws-amplify/amplify-js/commit/50611fe)) - - - +- **aws-amplify-angular:** authState visibility issues on initial load ([#1657](https://github.com/aws-amplify/amplify-js/issues/1657)) ([50611fe](https://github.com/aws-amplify/amplify-js/commit/50611fe)) -## [2.0.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.2...aws-amplify-angular@2.0.3) (2018-09-12) - - +## [2.0.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.2...aws-amplify-angular@2.0.3) (2018-09-12) **Note:** Version bump only for package aws-amplify-angular -## [2.0.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.2-unstable.0...aws-amplify-angular@2.0.2) (2018-09-09) - - +## [2.0.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.2-unstable.0...aws-amplify-angular@2.0.2) (2018-09-09) **Note:** Version bump only for package aws-amplify-angular -## [2.0.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.1...aws-amplify-angular@2.0.2-unstable.0) (2018-09-09) - - +## [2.0.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.1...aws-amplify-angular@2.0.2-unstable.0) (2018-09-09) **Note:** Version bump only for package aws-amplify-angular -## [2.0.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.1-unstable.2...aws-amplify-angular@2.0.1) (2018-09-09) - - +## [2.0.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.1-unstable.2...aws-amplify-angular@2.0.1) (2018-09-09) **Note:** Version bump only for package aws-amplify-angular -## [2.0.1-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.0...aws-amplify-angular@2.0.1-unstable.2) (2018-09-06) - - +## [2.0.1-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.0...aws-amplify-angular@2.0.1-unstable.2) (2018-09-06) **Note:** Version bump only for package aws-amplify-angular -## [2.0.1-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.0...aws-amplify-angular@2.0.1-unstable.1) (2018-08-30) - - +## [2.0.1-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@2.0.0...aws-amplify-angular@2.0.1-unstable.1) (2018-08-30) **Note:** Version bump only for package aws-amplify-angular -# [2.0.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.4-unstable.3...aws-amplify-angular@2.0.0) (2018-08-28) +# [2.0.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.4-unstable.3...aws-amplify-angular@2.0.0) (2018-08-28) ### Features -* UI Components ([1ff1abd](https://github.com/aws-amplify/amplify-js/commit/1ff1abd)) - +- UI Components ([1ff1abd](https://github.com/aws-amplify/amplify-js/commit/1ff1abd)) ### BREAKING CHANGES -* UI Components - - - +- UI Components -## [1.0.4-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.4-unstable.2...aws-amplify-angular@1.0.4-unstable.3) (2018-08-28) +## [1.0.4-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.4-unstable.2...aws-amplify-angular@1.0.4-unstable.3) (2018-08-28) -* Amplify ui migration (#1517) ([41d3184](https://github.com/aws-amplify/amplify-js/commit/41d3184)), closes [#1517](https://github.com/aws-amplify/amplify-js/issues/1517) - +- Amplify ui migration (#1517) ([41d3184](https://github.com/aws-amplify/amplify-js/commit/41d3184)), closes [#1517](https://github.com/aws-amplify/amplify-js/issues/1517) ### BREAKING CHANGES -* UI Components - - - +- UI Components -## [1.0.4-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.4-unstable.1...aws-amplify-angular@1.0.4-unstable.2) (2018-08-23) - - +## [1.0.4-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.4-unstable.1...aws-amplify-angular@1.0.4-unstable.2) (2018-08-23) **Note:** Version bump only for package aws-amplify-angular -## [1.0.4-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.4-unstable.0...aws-amplify-angular@1.0.4-unstable.1) (2018-08-20) - - +## [1.0.4-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.4-unstable.0...aws-amplify-angular@1.0.4-unstable.1) (2018-08-20) **Note:** Version bump only for package aws-amplify-angular -## [1.0.4-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.3...aws-amplify-angular@1.0.4-unstable.0) (2018-08-19) +## [1.0.4-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.3...aws-amplify-angular@1.0.4-unstable.0) (2018-08-19) ### Bug Fixes -* **aws-amplify-angular:** Angular rollup ([#1441](https://github.com/aws-amplify/amplify-js/issues/1441)) ([eb84e01](https://github.com/aws-amplify/amplify-js/commit/eb84e01)) - - - +- **aws-amplify-angular:** Angular rollup ([#1441](https://github.com/aws-amplify/amplify-js/issues/1441)) ([eb84e01](https://github.com/aws-amplify/amplify-js/commit/eb84e01)) -## [1.0.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.2-unstable.2...aws-amplify-angular@1.0.3) (2018-08-06) - - +## [1.0.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.2-unstable.2...aws-amplify-angular@1.0.3) (2018-08-06) **Note:** Version bump only for package aws-amplify-angular -## [1.0.2-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.2...aws-amplify-angular@1.0.2-unstable.2) (2018-08-06) - - +## [1.0.2-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.2...aws-amplify-angular@1.0.2-unstable.2) (2018-08-06) **Note:** Version bump only for package aws-amplify-angular -## [1.0.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.2-unstable.1...aws-amplify-angular@1.0.2) (2018-07-28) - - +## [1.0.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.2-unstable.1...aws-amplify-angular@1.0.2) (2018-07-28) **Note:** Version bump only for package aws-amplify-angular -## [1.0.2-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.2-unstable.0...aws-amplify-angular@1.0.2-unstable.1) (2018-07-24) - - +## [1.0.2-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.2-unstable.0...aws-amplify-angular@1.0.2-unstable.1) (2018-07-24) **Note:** Version bump only for package aws-amplify-angular -## [1.0.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.1...aws-amplify-angular@1.0.2-unstable.0) (2018-07-20) - - +## [1.0.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.1...aws-amplify-angular@1.0.2-unstable.0) (2018-07-20) **Note:** Version bump only for package aws-amplify-angular -## [1.0.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.1-unstable.1...aws-amplify-angular@1.0.1) (2018-07-18) - - +## [1.0.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.1-unstable.1...aws-amplify-angular@1.0.1) (2018-07-18) **Note:** Version bump only for package aws-amplify-angular -## [1.0.1-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.1...aws-amplify-angular@1.0.1-unstable.1) (2018-07-18) - - +## [1.0.1-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@1.0.1...aws-amplify-angular@1.0.1-unstable.1) (2018-07-18) **Note:** Version bump only for package aws-amplify-angular -## [1.0.1-unstable.0](https://github.com/powerful23/aws-amplify/compare/aws-amplify-angular@1.0.1...aws-amplify-angular@1.0.1-unstable.0) (2018-07-18) - - +## [1.0.1-unstable.0](https://github.com/powerful23/aws-amplify/compare/aws-amplify-angular@1.0.1...aws-amplify-angular@1.0.1-unstable.0) (2018-07-18) **Note:** Version bump only for package aws-amplify-angular -## [0.1.6](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.5-unstable.0...aws-amplify-angular@0.1.6) (2018-06-21) - - +## [0.1.6](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.5-unstable.0...aws-amplify-angular@0.1.6) (2018-06-21) **Note:** Version bump only for package aws-amplify-angular -## [0.1.5](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.4...aws-amplify-angular@0.1.5) (2018-06-20) - -## [0.1.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.4...aws-amplify-angular@0.1.5-unstable.0) (2018-06-20) +## [0.1.5](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.4...aws-amplify-angular@0.1.5) (2018-06-20) + +## [0.1.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.4...aws-amplify-angular@0.1.5-unstable.0) (2018-06-20) **Note:** Version bump only for package aws-amplify-angular -## [0.1.4](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.3...aws-amplify-angular@0.1.4) (2018-06-04) - - +## [0.1.4](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.3...aws-amplify-angular@0.1.4) (2018-06-04) **Note:** Version bump only for package aws-amplify-angular -## [0.1.3](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.3-unstable.1...aws-amplify-angular@0.1.3) (2018-06-01) - - +## [0.1.3](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.3-unstable.1...aws-amplify-angular@0.1.3) (2018-06-01) **Note:** Version bump only for package aws-amplify-angular -## [0.1.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.2-unstable.4...aws-amplify-angular@0.1.3-unstable.1) (2018-06-01) - - +## [0.1.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.2-unstable.4...aws-amplify-angular@0.1.3-unstable.1) (2018-06-01) **Note:** Version bump only for package aws-amplify-angular -## [0.1.2-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.2-unstable.3...aws-amplify-angular@0.1.2-unstable.4) (2018-05-30) - - +## [0.1.2-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.2-unstable.3...aws-amplify-angular@0.1.2-unstable.4) (2018-05-30) **Note:** Version bump only for package aws-amplify-angular -## [0.1.2-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.1...aws-amplify-angular@0.1.2-unstable.3) (2018-05-24) - - +## [0.1.2-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-angular@0.1.1...aws-amplify-angular@0.1.2-unstable.3) (2018-05-24) **Note:** Version bump only for package aws-amplify-angular -## [0.1.2-unstable.2](https://github.com/mlabieniec/aws-amplify/compare/aws-amplify-angular@0.1.2-unstable.1...aws-amplify-angular@0.1.2-unstable.2) (2018-05-24) - - +## [0.1.2-unstable.2](https://github.com/mlabieniec/aws-amplify/compare/aws-amplify-angular@0.1.2-unstable.1...aws-amplify-angular@0.1.2-unstable.2) (2018-05-24) **Note:** Version bump only for package aws-amplify-angular diff --git a/packages/aws-amplify-angular/index.ts b/packages/aws-amplify-angular/index.ts index 47d58486f3f..3a1933e0e8d 100644 --- a/packages/aws-amplify-angular/index.ts +++ b/packages/aws-amplify-angular/index.ts @@ -1,4 +1,3 @@ export { AmplifyAngularModule } from './src/aws-amplify-angular.module'; export { AmplifyIonicModule } from './src/aws-amplify-ionic-module'; -export { AmplifyService, AmplifyModules} from './src/providers'; - +export { AmplifyService, AmplifyModules } from './src/providers'; diff --git a/packages/aws-amplify-angular/jest.config.js b/packages/aws-amplify-angular/jest.config.js index 7b86bef6604..8745d831aed 100644 --- a/packages/aws-amplify-angular/jest.config.js +++ b/packages/aws-amplify-angular/jest.config.js @@ -1,6 +1,6 @@ module.exports = { - preset: "jest-preset-angular", - roots: ['src'], - setupTestFrameworkScriptFile: "/test_setup/setup-jest.ts", - testURL: 'http://localhost/' -} + preset: 'jest-preset-angular', + roots: ['src'], + setupTestFrameworkScriptFile: '/test_setup/setup-jest.ts', + testURL: 'http://localhost/', +}; diff --git a/packages/aws-amplify-angular/rollup.config.js b/packages/aws-amplify-angular/rollup.config.js index ea9a1b89851..50043e5ce95 100644 --- a/packages/aws-amplify-angular/rollup.config.js +++ b/packages/aws-amplify-angular/rollup.config.js @@ -8,35 +8,40 @@ import { uglify } from 'rollup-plugin-uglify'; import json from 'rollup-plugin-json'; export default { - input: 'dist/index.js', - output: { - name: 'aws-amplify-angular', - file: 'dist/bundles/aws-amplify-angular.umd.js', - format: 'umd', - globals: { - 'lodash': '_', - '@ionic/angular': 'IonicModule', - 'aws-amplify': 'Amplify', - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - 'rxjs/Observable': 'Rx', - 'rxjs/Subscription': 'Rx', - 'rxjs/ReplaySubject': 'Rx', - 'rxjs/add/operator/map': 'Rx.Observable.prototype', - 'rxjs/add/operator/mergeMap': 'Rx.Observable.prototype', - 'rxjs/add/observable/fromEvent': 'Rx.Observable', - 'rxjs/add/observable/of': 'Rx.Observable' - }, - }, - external: ['aws-sdk' ,'@angular/core', '@angular/common', 'aws-amplify', '@ionic/angular'], - plugins: [ - nodeResolve({ preferBuiltins: false, modulesOnly: true }), - commonjs({include: 'node_modules/**'}), - globals(), - builtins(), - json(), - uglify(), - analyze({limit: 1}) - ] - -} \ No newline at end of file + input: 'dist/index.js', + output: { + name: 'aws-amplify-angular', + file: 'dist/bundles/aws-amplify-angular.umd.js', + format: 'umd', + globals: { + lodash: '_', + '@ionic/angular': 'IonicModule', + 'aws-amplify': 'Amplify', + '@angular/core': 'ng.core', + '@angular/common': 'ng.common', + 'rxjs/Observable': 'Rx', + 'rxjs/Subscription': 'Rx', + 'rxjs/ReplaySubject': 'Rx', + 'rxjs/add/operator/map': 'Rx.Observable.prototype', + 'rxjs/add/operator/mergeMap': 'Rx.Observable.prototype', + 'rxjs/add/observable/fromEvent': 'Rx.Observable', + 'rxjs/add/observable/of': 'Rx.Observable', + }, + }, + external: [ + 'aws-sdk', + '@angular/core', + '@angular/common', + 'aws-amplify', + '@ionic/angular', + ], + plugins: [ + nodeResolve({ preferBuiltins: false, modulesOnly: true }), + commonjs({ include: 'node_modules/**' }), + globals(), + builtins(), + json(), + uglify(), + analyze({ limit: 1 }), + ], +}; diff --git a/packages/aws-amplify-angular/src/__mocks__/mock_module.ts b/packages/aws-amplify-angular/src/__mocks__/mock_module.ts index 253e04f9061..be846916dbf 100644 --- a/packages/aws-amplify-angular/src/__mocks__/mock_module.ts +++ b/packages/aws-amplify-angular/src/__mocks__/mock_module.ts @@ -1,83 +1,79 @@ const authModule = { - Auth: { - signIn: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - signUp: () => { - return new Promise((resolve, reject) => { - resolve({username: 'fakename'}); - }); - }, - confirmSignIn: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - confirmSignUp: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - completeNewPassword: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - forgotPassword: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - forgotPasswordSubmit: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - signOut: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - currentAuthenticatedUser: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - setAuthState: () => { - return 1; - } - } + Auth: { + signIn: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + signUp: () => { + return new Promise((resolve, reject) => { + resolve({ username: 'fakename' }); + }); + }, + confirmSignIn: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + confirmSignUp: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + completeNewPassword: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + forgotPassword: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + forgotPasswordSubmit: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + signOut: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + currentAuthenticatedUser: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + setAuthState: () => { + return 1; + }, + }, }; const interactionsModule = { - Interactions: { - onComplete: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - send: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - } -} + Interactions: { + onComplete: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + send: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + }, +}; const storageModule = { - Storage: { - put: () => { - return new Promise((resolve, reject) => { - resolve(1); - }) - } - } -} - -export { - authModule, - interactionsModule, - storageModule + Storage: { + put: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + }, }; + +export { authModule, interactionsModule, storageModule }; diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/authenticator.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/authenticator.component.core.spec.ts index bd6a2fc3efe..23c334fd58e 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/authenticator.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/authenticator.component.core.spec.ts @@ -1,48 +1,46 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed, async } from '@angular/core/testing'; -import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, +} from '@angular/platform-browser-dynamic/testing'; import Amplify from 'aws-amplify'; import { AmplifyService } from '../../../providers/amplify.service'; -import { AuthenticatorComponentCore } from '../../../components/authenticator/authenticator/authenticator.component.core' - +import { AuthenticatorComponentCore } from '../../../components/authenticator/authenticator/authenticator.component.core'; describe('AuthenticatorComponentCore: ', () => { - - let component: AuthenticatorComponentCore; - let service: AmplifyService; - - beforeEach(() => { - service = new AmplifyService(Amplify); - component = new AuthenticatorComponentCore(service); - }); - - afterEach(() => { - service = null; - component = null; - }); - - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have a subscribe method', () => { - expect(component.subscribe).toBeTruthy(); - }); - - it('...should have a shouldHide method', () => { - expect(component.shouldHide).toBeTruthy(); - }); - - it('...the shouldHide method should return false when receiving a value not in the hide array', () => { - component.hide = ['value one', 'value two']; - expect(component.shouldHide('value three')).toEqual(false); - }); - - it('...the shouldHide method should return true when receiving a value in the hide array', () => { - component.hide = ['value one', 'value two']; - expect(component.shouldHide('value two')).toEqual(true); - }) - - -}); \ No newline at end of file + let component: AuthenticatorComponentCore; + let service: AmplifyService; + + beforeEach(() => { + service = new AmplifyService(Amplify); + component = new AuthenticatorComponentCore(service); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have a subscribe method', () => { + expect(component.subscribe).toBeTruthy(); + }); + + it('...should have a shouldHide method', () => { + expect(component.shouldHide).toBeTruthy(); + }); + + it('...the shouldHide method should return false when receiving a value not in the hide array', () => { + component.hide = ['value one', 'value two']; + expect(component.shouldHide('value three')).toEqual(false); + }); + + it('...the shouldHide method should return true when receiving a value in the hide array', () => { + component.hide = ['value one', 'value two']; + expect(component.shouldHide('value two')).toEqual(true); + }); +}); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/authenticator.component.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/authenticator.component.ionic.spec.ts index 4f5faac58ec..1bc769dc57a 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/authenticator.component.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/authenticator.component.ionic.spec.ts @@ -1,46 +1,46 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, +} from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; -import { AuthenticatorIonicComponent } from '../../../components/authenticator/authenticator/authenticator.component.ionic' - +import { AuthenticatorIonicComponent } from '../../../components/authenticator/authenticator/authenticator.component.ionic'; describe('AuthenticatorIonicComponent: ', () => { - - let component: AuthenticatorIonicComponent; - let service: AmplifyService; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new AuthenticatorIonicComponent(service); - }); - - afterEach(() => { - service = null; - component = null; - }); - - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have a subscribe method', () => { - expect(component.subscribe).toBeTruthy(); - }); - - it('...should have a shouldHide method', () => { - expect(component.shouldHide).toBeTruthy(); - }); - - it('...the shouldHide method should return false when receiving a value not in the hide array', () => { - component.hide = ['value one', 'value two']; - expect(component.shouldHide('value three')).toEqual(false); - }); - - it('...the shouldHide method should return true when receiving a value in the hide array', () => { - component.hide = ['value one', 'value two']; - expect(component.shouldHide('value two')).toEqual(true); - }) + let component: AuthenticatorIonicComponent; + let service: AmplifyService; + + beforeEach(() => { + service = new AmplifyService(authModule); + component = new AuthenticatorIonicComponent(service); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have a subscribe method', () => { + expect(component.subscribe).toBeTruthy(); + }); + + it('...should have a shouldHide method', () => { + expect(component.shouldHide).toBeTruthy(); + }); + + it('...the shouldHide method should return false when receiving a value not in the hide array', () => { + component.hide = ['value one', 'value two']; + expect(component.shouldHide('value three')).toEqual(false); + }); + + it('...the shouldHide method should return true when receiving a value in the hide array', () => { + component.hide = ['value one', 'value two']; + expect(component.shouldHide('value two')).toEqual(true); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-in.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-in.component.core.spec.ts index 24cb8e4ada1..acb146aadc6 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-in.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-in.component.core.spec.ts @@ -1,130 +1,135 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, platformBrowserDynamicTesting, +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { AmplifyAngularModule } from '../../../aws-amplify-angular.module'; import { authModule } from '../../../__mocks__/mock_module'; -import { ConfirmSignInComponentCore } -from '../../../components/authenticator/confirm-sign-in-component/confirm-sign-in-component.core'; - +import { ConfirmSignInComponentCore } from '../../../components/authenticator/confirm-sign-in-component/confirm-sign-in-component.core'; describe('ConfirmSignInComponentCore: ', () => { - - let component: ConfirmSignInComponentCore; - let fixtureComponent: ConfirmSignInComponentCore; - let service: AmplifyService; - let fixture; - let setAuthStateSpy; - let confirmSignInSpy; - let onConfirmSpy; - let onSignInSpy; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new ConfirmSignInComponentCore(service); - setAuthStateSpy = jest.spyOn(service, 'setAuthState'); - confirmSignInSpy = jest.spyOn(service.auth(), 'confirmSignIn'); - TestBed.configureTestingModule({ - declarations: [ - ConfirmSignInComponentCore - ], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - }).compileComponents(); - fixture = TestBed.createComponent(ConfirmSignInComponentCore); - fixtureComponent = fixture.componentInstance; - onConfirmSpy = jest.spyOn(fixtureComponent, 'onConfirm'); - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - }); - - afterEach(() => { - service = null; - component = null; - fixtureComponent = null; - }); - - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have a setCode method', () => { - expect(component.setCode).toBeTruthy(); - }); - - it('...should have a code property that is initally undefined', () => { - expect(component.code).toBeUndefined(); - }); - - it('...the setCode method should set the component\'s code property', () => { - component.setCode('200'); - expect(component.code).toEqual('200'); - }); - - it('...should have an onConfirm method', () => { - expect(component.onConfirm).toBeTruthy(); - }); - - it('...should call confirmSignIn within the onConfirm method', () => { - component._authState = {user: {challengeName: 'test-challange-name'}, state: 'test-state'}; - const callingAuthState = component.onConfirm(); - expect(service.auth().confirmSignIn).toBeCalled(); - }); - - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); - - it('...should call setAuthState within the onSignIn method', () => { - const callingAuthState = component.onSignIn(); - expect(service.setAuthState).toBeCalled(); - }); - - it('...should have a _setError method', () => { - expect(component._setError).toBeTruthy(); - }); - - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeFalsy(); - }); - - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeTruthy(); - }); - - it('...should call onConfirm when button is clicked', () => { - fixtureComponent._show = true; - fixtureComponent._authState = { - state: 'confirmSignIn', - user: {} - }; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('.amplify-form-button'); - button.click(); - expect(onConfirmSpy).toHaveBeenCalled(); - expect(confirmSignInSpy).toHaveBeenCalled(); - }); - - it('...should call onSignIn when "a" tag is clicked', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const a = fixture.debugElement.nativeElement.querySelector('.amplify-form-link'); - a.click(); - expect(onSignInSpy).toHaveBeenCalled(); - }); - + let component: ConfirmSignInComponentCore; + let fixtureComponent: ConfirmSignInComponentCore; + let service: AmplifyService; + let fixture; + let setAuthStateSpy; + let confirmSignInSpy; + let onConfirmSpy; + let onSignInSpy; + + beforeEach(() => { + service = new AmplifyService(authModule); + component = new ConfirmSignInComponentCore(service); + setAuthStateSpy = jest.spyOn(service, 'setAuthState'); + confirmSignInSpy = jest.spyOn(service.auth(), 'confirmSignIn'); + TestBed.configureTestingModule({ + declarations: [ConfirmSignInComponentCore], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(ConfirmSignInComponentCore); + fixtureComponent = fixture.componentInstance; + onConfirmSpy = jest.spyOn(fixtureComponent, 'onConfirm'); + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + }); + + afterEach(() => { + service = null; + component = null; + fixtureComponent = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have a setCode method', () => { + expect(component.setCode).toBeTruthy(); + }); + + it('...should have a code property that is initally undefined', () => { + expect(component.code).toBeUndefined(); + }); + + it("...the setCode method should set the component's code property", () => { + component.setCode('200'); + expect(component.code).toEqual('200'); + }); + + it('...should have an onConfirm method', () => { + expect(component.onConfirm).toBeTruthy(); + }); + + it('...should call confirmSignIn within the onConfirm method', () => { + component._authState = { + user: { challengeName: 'test-challange-name' }, + state: 'test-state', + }; + const callingAuthState = component.onConfirm(); + expect(service.auth().confirmSignIn).toBeCalled(); + }); + + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); + + it('...should call setAuthState within the onSignIn method', () => { + const callingAuthState = component.onSignIn(); + expect(service.setAuthState).toBeCalled(); + }); + + it('...should have a _setError method', () => { + expect(component._setError).toBeTruthy(); + }); + + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeFalsy(); + }); + + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeTruthy(); + }); + + it('...should call onConfirm when button is clicked', () => { + fixtureComponent._show = true; + fixtureComponent._authState = { + state: 'confirmSignIn', + user: {}, + }; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-button' + ); + button.click(); + expect(onConfirmSpy).toHaveBeenCalled(); + expect(confirmSignInSpy).toHaveBeenCalled(); + }); + + it('...should call onSignIn when "a" tag is clicked', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const a = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-link' + ); + a.click(); + expect(onSignInSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-in.component.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-in.component.ionic.spec.ts index fd23612d4ee..962cf2df61b 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-in.component.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-in.component.ionic.spec.ts @@ -1,144 +1,147 @@ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, platformBrowserDynamicTesting, +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { AmplifyAngularModule } from '../../../aws-amplify-angular.module'; import { authModule } from '../../../__mocks__/mock_module'; -import { ConfirmSignInComponentIonic } -from '../../../components/authenticator/confirm-sign-in-component/confirm-sign-in-component.ionic'; - +import { ConfirmSignInComponentIonic } from '../../../components/authenticator/confirm-sign-in-component/confirm-sign-in-component.ionic'; describe('ConfirmSignInComponentIonic: ', () => { - - let component: ConfirmSignInComponentIonic; - let fixtureComponent: ConfirmSignInComponentIonic; - let service: AmplifyService; - let fixture; - let setAuthStateSpy; - let confirmSignInSpy; - let onConfirmSpy; - let onSignInSpy; - - const modules = { - Auth: { - confirmSignIn: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - currentAuthenticatedUser: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - }, - setAuthState: () => { - return new Promise((resolve, reject) => { - resolve(1); - }); - } - } - }; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new ConfirmSignInComponentIonic(service); - setAuthStateSpy = jest.spyOn(service, 'setAuthState'); - confirmSignInSpy = jest.spyOn(service.auth(), 'confirmSignIn'); - TestBed.configureTestingModule({ - declarations: [ - ConfirmSignInComponentIonic - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - }).compileComponents(); - fixture = TestBed.createComponent(ConfirmSignInComponentIonic); - fixtureComponent = fixture.componentInstance; - onConfirmSpy = jest.spyOn(fixtureComponent, 'onConfirm'); - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - }); - - afterEach(() => { - service = null; - component = null; - fixtureComponent = null; - }); - - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have a setCode method', () => { - expect(component.setCode).toBeTruthy(); - }); - - it('...should have a code property that is initally undefined', () => { - expect(component.code).toBeUndefined(); - }); - - it('...the setCode method should set the component\'s code property', () => { - component.setCode('200'); - expect(component.code).toEqual('200'); - }); - - it('...should have an onConfirm method', () => { - expect(component.onConfirm).toBeTruthy(); - }); - - it('...should call confirmSignIn within the onConfirm method', () => { - component._authState = {user: {challengeName: 'test-challange-name'}, state: 'test-state'}; - const callingAuthState = component.onConfirm(); - expect(service.auth().confirmSignIn).toBeCalled(); - }); - - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); - - it('...should call setAuthState within the onSignIn method', () => { - const callingAuthState = component.onSignIn(); - expect(service.setAuthState).toBeCalled(); - }); - - it('...should have a _setError method', () => { - expect(component._setError).toBeTruthy(); - }); - - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-form-container'); - expect(rootEl).toBeFalsy(); - }); - - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-form-container'); - expect(rootEl).toBeTruthy(); - }); - - it('...should call onConfirm when button is clicked', () => { - fixtureComponent._show = true; - fixtureComponent._authState = { - state: 'confirmSignIn', - user: {} - }; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('ion-button'); - button.click(); - expect(onConfirmSpy).toHaveBeenCalled(); - expect(confirmSignInSpy).toHaveBeenCalled(); - }); - + let component: ConfirmSignInComponentIonic; + let fixtureComponent: ConfirmSignInComponentIonic; + let service: AmplifyService; + let fixture; + let setAuthStateSpy; + let confirmSignInSpy; + let onConfirmSpy; + let onSignInSpy; + + const modules = { + Auth: { + confirmSignIn: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + currentAuthenticatedUser: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + setAuthState: () => { + return new Promise((resolve, reject) => { + resolve(1); + }); + }, + }, + }; + + beforeEach(() => { + service = new AmplifyService(authModule); + component = new ConfirmSignInComponentIonic(service); + setAuthStateSpy = jest.spyOn(service, 'setAuthState'); + confirmSignInSpy = jest.spyOn(service.auth(), 'confirmSignIn'); + TestBed.configureTestingModule({ + declarations: [ConfirmSignInComponentIonic], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(ConfirmSignInComponentIonic); + fixtureComponent = fixture.componentInstance; + onConfirmSpy = jest.spyOn(fixtureComponent, 'onConfirm'); + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + }); + + afterEach(() => { + service = null; + component = null; + fixtureComponent = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have a setCode method', () => { + expect(component.setCode).toBeTruthy(); + }); + + it('...should have a code property that is initally undefined', () => { + expect(component.code).toBeUndefined(); + }); + + it("...the setCode method should set the component's code property", () => { + component.setCode('200'); + expect(component.code).toEqual('200'); + }); + + it('...should have an onConfirm method', () => { + expect(component.onConfirm).toBeTruthy(); + }); + + it('...should call confirmSignIn within the onConfirm method', () => { + component._authState = { + user: { challengeName: 'test-challange-name' }, + state: 'test-state', + }; + const callingAuthState = component.onConfirm(); + expect(service.auth().confirmSignIn).toBeCalled(); + }); + + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); + + it('...should call setAuthState within the onSignIn method', () => { + const callingAuthState = component.onSignIn(); + expect(service.setAuthState).toBeCalled(); + }); + + it('...should have a _setError method', () => { + expect(component._setError).toBeTruthy(); + }); + + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-container' + ); + expect(rootEl).toBeFalsy(); + }); + + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-container' + ); + expect(rootEl).toBeTruthy(); + }); + + it('...should call onConfirm when button is clicked', () => { + fixtureComponent._show = true; + fixtureComponent._authState = { + state: 'confirmSignIn', + user: {}, + }; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + 'ion-button' + ); + button.click(); + expect(onConfirmSpy).toHaveBeenCalled(); + expect(confirmSignInSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-up.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-up.component.core.spec.ts index 46ad4e16433..19ca281954e 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-up.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-up.component.core.spec.ts @@ -1,110 +1,114 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule,platformBrowserDynamicTesting +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; -import { ConfirmSignUpComponentCore } -from '../../../components/authenticator/confirm-sign-up-component/confirm-sign-up.component.core'; - +import { ConfirmSignUpComponentCore } from '../../../components/authenticator/confirm-sign-up-component/confirm-sign-up.component.core'; describe('ConfirmSignUpComponentCore: ', () => { + let component: ConfirmSignUpComponentCore; + let fixtureComponent: ConfirmSignUpComponentCore; + let service: AmplifyService; + let fixture; + let onSignInSpy; + let onConfirmSpy; + let confirmSignUpSpy; - let component: ConfirmSignUpComponentCore; - let fixtureComponent: ConfirmSignUpComponentCore; - let service: AmplifyService; - let fixture; - let onSignInSpy; - let onConfirmSpy; - let confirmSignUpSpy; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new ConfirmSignUpComponentCore(service); - TestBed.configureTestingModule({ - declarations: [ - ConfirmSignUpComponentCore - ], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - }).compileComponents(); - fixture = TestBed.createComponent(ConfirmSignUpComponentCore); - fixtureComponent = fixture.componentInstance; - confirmSignUpSpy = jest.spyOn(service.auth(), 'confirmSignUp'); - onConfirmSpy = jest.spyOn(fixtureComponent, 'onConfirm'); - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - }); + beforeEach(() => { + service = new AmplifyService(authModule); + component = new ConfirmSignUpComponentCore(service); + TestBed.configureTestingModule({ + declarations: [ConfirmSignUpComponentCore], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(ConfirmSignUpComponentCore); + fixtureComponent = fixture.componentInstance; + confirmSignUpSpy = jest.spyOn(service.auth(), 'confirmSignUp'); + onConfirmSpy = jest.spyOn(fixtureComponent, 'onConfirm'); + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + }); - afterEach(() => { - service = null; - component = null; - fixtureComponent = null; - }); + afterEach(() => { + service = null; + component = null; + fixtureComponent = null; + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); + it('...should be created', () => { + expect(component).toBeTruthy(); + }); - it('...should have an onConfirm method', () => { - expect(component.onConfirm).toBeTruthy(); - }); + it('...should have an onConfirm method', () => { + expect(component.onConfirm).toBeTruthy(); + }); - it('...should have an onResend method', () => { - expect(component.onResend).toBeTruthy(); - }); + it('...should have an onResend method', () => { + expect(component.onResend).toBeTruthy(); + }); - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); - it('...should have an setCode method', () => { - expect(component.setCode).toBeTruthy(); - }); + it('...should have an setCode method', () => { + expect(component.setCode).toBeTruthy(); + }); - it('...should have an setUsername method', () => { - expect(component.setUsername).toBeTruthy(); - }); + it('...should have an setUsername method', () => { + expect(component.setUsername).toBeTruthy(); + }); - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeFalsy(); - }); + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeFalsy(); + }); - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeTruthy(); - }); + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeTruthy(); + }); - it('...should call onConfirm when button is clicked', () => { - fixtureComponent._show = true; - fixtureComponent._authState = { - state: 'confirmSignIn', - user: {} - }; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('.amplify-form-button'); - button.click(); - expect(onConfirmSpy).toHaveBeenCalled(); - expect(confirmSignUpSpy).toHaveBeenCalled(); - }); + it('...should call onConfirm when button is clicked', () => { + fixtureComponent._show = true; + fixtureComponent._authState = { + state: 'confirmSignIn', + user: {}, + }; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-button' + ); + button.click(); + expect(onConfirmSpy).toHaveBeenCalled(); + expect(confirmSignUpSpy).toHaveBeenCalled(); + }); - it('...should call onSignIn when "a" tag is clicked', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const parent = fixture.debugElement.nativeElement.querySelector('.amplify-form-actions-left'); - const a = parent.querySelector('.amplify-form-link'); - a.click(); - expect(onSignInSpy).toHaveBeenCalled(); - }); + it('...should call onSignIn when "a" tag is clicked', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const parent = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-actions-left' + ); + const a = parent.querySelector('.amplify-form-link'); + a.click(); + expect(onSignInSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-up.component.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-up.component.ionic.spec.ts index f330b86f73d..537278223e5 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-up.component.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/confirm-sign-up.component.ionic.spec.ts @@ -1,99 +1,99 @@ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; -import { ConfirmSignUpComponentIonic } -from '../../../components/authenticator/confirm-sign-up-component/confirm-sign-up.component.ionic'; - +import { ConfirmSignUpComponentIonic } from '../../../components/authenticator/confirm-sign-up-component/confirm-sign-up.component.ionic'; describe('ConfirmSignUpComponentIonic: ', () => { + let component: ConfirmSignUpComponentIonic; + let fixtureComponent: ConfirmSignUpComponentIonic; + let service: AmplifyService; + let fixture; + let onSignInSpy; + let onConfirmSpy; + let confirmSignUpSpy; - let component: ConfirmSignUpComponentIonic; - let fixtureComponent: ConfirmSignUpComponentIonic; - let service: AmplifyService; - let fixture; - let onSignInSpy; - let onConfirmSpy; - let confirmSignUpSpy; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new ConfirmSignUpComponentIonic(service); - TestBed.configureTestingModule({ - declarations: [ - ConfirmSignUpComponentIonic - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - }).compileComponents(); - fixture = TestBed.createComponent(ConfirmSignUpComponentIonic); - fixtureComponent = fixture.componentInstance; - confirmSignUpSpy = jest.spyOn(service.auth(), 'confirmSignUp'); - onConfirmSpy = jest.spyOn(fixtureComponent, 'onConfirm'); - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - }); - - afterEach(() => { - service = null; - component = null; - }); + beforeEach(() => { + service = new AmplifyService(authModule); + component = new ConfirmSignUpComponentIonic(service); + TestBed.configureTestingModule({ + declarations: [ConfirmSignUpComponentIonic], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(ConfirmSignUpComponentIonic); + fixtureComponent = fixture.componentInstance; + confirmSignUpSpy = jest.spyOn(service.auth(), 'confirmSignUp'); + onConfirmSpy = jest.spyOn(fixtureComponent, 'onConfirm'); + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + }); + afterEach(() => { + service = null; + component = null; + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); + it('...should be created', () => { + expect(component).toBeTruthy(); + }); - it('...should have an onConfirm method', () => { - expect(component.onConfirm).toBeTruthy(); - }); + it('...should have an onConfirm method', () => { + expect(component.onConfirm).toBeTruthy(); + }); - it('...should have an onResend method', () => { - expect(component.onResend).toBeTruthy(); - }); + it('...should have an onResend method', () => { + expect(component.onResend).toBeTruthy(); + }); - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); - it('...should have an setCode method', () => { - expect(component.setCode).toBeTruthy(); - }); + it('...should have an setCode method', () => { + expect(component.setCode).toBeTruthy(); + }); - it('...should have an setUsername method', () => { - expect(component.setUsername).toBeTruthy(); - }); + it('...should have an setUsername method', () => { + expect(component.setUsername).toBeTruthy(); + }); - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-authenticator-ionic'); - expect(rootEl).toBeFalsy(); - }); + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-authenticator-ionic' + ); + expect(rootEl).toBeFalsy(); + }); - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-authenticator-ionic'); - expect(rootEl).toBeTruthy(); - }); + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-authenticator-ionic' + ); + expect(rootEl).toBeTruthy(); + }); - it('...should call onConfirm when ion-button is clicked', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('ion-button'); - button.click(); - expect(onConfirmSpy).toHaveBeenCalled(); - expect(confirmSignUpSpy).toHaveBeenCalled(); - }); + it('...should call onConfirm when ion-button is clicked', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + 'ion-button' + ); + button.click(); + expect(onConfirmSpy).toHaveBeenCalled(); + expect(confirmSignUpSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/forgot-password.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/forgot-password.component.core.spec.ts index 2dd5fb91b84..a42651727aa 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/forgot-password.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/forgot-password.component.core.spec.ts @@ -3,153 +3,164 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { MockComponent } from 'ng-mocks'; import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; -import { ForgotPasswordComponentCore } -from '../../../components/authenticator/forgot-password-component/forgot-password.component.core'; -import { UsernameFieldComponentCore } -from '../../../components/authenticator/username-field-component/username-field.component.core'; +import { ForgotPasswordComponentCore } from '../../../components/authenticator/forgot-password-component/forgot-password.component.core'; +import { UsernameFieldComponentCore } from '../../../components/authenticator/username-field-component/username-field.component.core'; describe('ForgotPasswordComponentCore: ', () => { - - let component: ForgotPasswordComponentCore; - let fixtureComponent: ForgotPasswordComponentCore; - let service: AmplifyService; - let fixture; - let onSubmitSpy; - let onSendSpy; - let forgotPasswordSpy; - let forgotPasswordSubmitSpy; - let onSignInSpy; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new ForgotPasswordComponentCore(service); - TestBed.configureTestingModule({ - declarations: [ - ForgotPasswordComponentCore, - MockComponent(UsernameFieldComponentCore) - ], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - imports: [FormsModule] - }).compileComponents(); - fixture = TestBed.createComponent(ForgotPasswordComponentCore); - fixtureComponent = fixture.componentInstance; - forgotPasswordSpy = jest.spyOn(service.auth(), 'forgotPassword'); - forgotPasswordSubmitSpy = jest.spyOn(service.auth(), 'forgotPasswordSubmit'); - onSubmitSpy = jest.spyOn(fixtureComponent, 'onSubmit'); - onSendSpy = jest.spyOn(fixtureComponent, 'onSend'); - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - }); - - afterEach(() => { - service = null; - component = null; - }); - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have an onSend method', () => { - expect(component.onSend).toBeTruthy(); - }); - - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); - - it('...should have an onSubmit method', () => { - expect(component.onSubmit).toBeTruthy(); - }); - - it('...should have an setCode method', () => { - expect(component.setCode).toBeTruthy(); - }); - - it('...should have an _setError method', () => { - expect(component._setError).toBeTruthy(); - }); - - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeFalsy(); - }); - - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeTruthy(); - }); - - it('...should call onSend when button is clicked and !codeSent', () => { - fixtureComponent._show = true; - fixtureComponent._authState = { - state: 'requireNewPassword', - user: {} - }; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('.amplify-form-button'); - button.click(); - expect(forgotPasswordSpy).not.toHaveBeenCalled(); - expect(onSendSpy).toHaveBeenCalled(); - fixtureComponent.username = 'username'; - fixture.detectChanges(); - button.click(); - expect(forgotPasswordSpy).toHaveBeenCalled(); - }); - - it('...should call onSubmit when button is clicked and codeSent', () => { - fixtureComponent._show = true; - fixtureComponent.code_sent = true; - fixtureComponent._authState = { - state: 'requireNewPassword', - user: {} - }; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('.amplify-form-button'); - button.click(); - expect(onSubmitSpy).toHaveBeenCalled(); - expect(forgotPasswordSubmitSpy).toHaveBeenCalled(); - }); - - - it('...should call onSend when a tag is clicked and codeSent', () => { - fixtureComponent._show = true; - fixtureComponent.code_sent = true; - fixtureComponent._authState = { - state: 'requireNewPassword', - user: {} - }; - fixture.detectChanges(); - const a = fixture.debugElement.nativeElement.querySelector('.amplify-form-link'); - a.click(); - expect(onSendSpy).toHaveBeenCalled(); - expect(forgotPasswordSpy).toHaveBeenCalled(); - }); - - it('...should call onSignIn when a tag is clicked and !codeSent', () => { - fixtureComponent._show = true; - fixtureComponent._authState = { - state: 'requireNewPassword', - user: {} - }; - fixture.detectChanges(); - const a = fixture.debugElement.nativeElement.querySelector('.amplify-form-link'); - a.click(); - expect(onSignInSpy).toHaveBeenCalled(); - }); + let component: ForgotPasswordComponentCore; + let fixtureComponent: ForgotPasswordComponentCore; + let service: AmplifyService; + let fixture; + let onSubmitSpy; + let onSendSpy; + let forgotPasswordSpy; + let forgotPasswordSubmitSpy; + let onSignInSpy; + + beforeEach(() => { + service = new AmplifyService(authModule); + component = new ForgotPasswordComponentCore(service); + TestBed.configureTestingModule({ + declarations: [ + ForgotPasswordComponentCore, + MockComponent(UsernameFieldComponentCore), + ], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + imports: [FormsModule], + }).compileComponents(); + fixture = TestBed.createComponent(ForgotPasswordComponentCore); + fixtureComponent = fixture.componentInstance; + forgotPasswordSpy = jest.spyOn(service.auth(), 'forgotPassword'); + forgotPasswordSubmitSpy = jest.spyOn( + service.auth(), + 'forgotPasswordSubmit' + ); + onSubmitSpy = jest.spyOn(fixtureComponent, 'onSubmit'); + onSendSpy = jest.spyOn(fixtureComponent, 'onSend'); + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have an onSend method', () => { + expect(component.onSend).toBeTruthy(); + }); + + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); + + it('...should have an onSubmit method', () => { + expect(component.onSubmit).toBeTruthy(); + }); + + it('...should have an setCode method', () => { + expect(component.setCode).toBeTruthy(); + }); + + it('...should have an _setError method', () => { + expect(component._setError).toBeTruthy(); + }); + + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeFalsy(); + }); + + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeTruthy(); + }); + + it('...should call onSend when button is clicked and !codeSent', () => { + fixtureComponent._show = true; + fixtureComponent._authState = { + state: 'requireNewPassword', + user: {}, + }; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-button' + ); + button.click(); + expect(forgotPasswordSpy).not.toHaveBeenCalled(); + expect(onSendSpy).toHaveBeenCalled(); + fixtureComponent.username = 'username'; + fixture.detectChanges(); + button.click(); + expect(forgotPasswordSpy).toHaveBeenCalled(); + }); + + it('...should call onSubmit when button is clicked and codeSent', () => { + fixtureComponent._show = true; + fixtureComponent.code_sent = true; + fixtureComponent._authState = { + state: 'requireNewPassword', + user: {}, + }; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-button' + ); + button.click(); + expect(onSubmitSpy).toHaveBeenCalled(); + expect(forgotPasswordSubmitSpy).toHaveBeenCalled(); + }); + + it('...should call onSend when a tag is clicked and codeSent', () => { + fixtureComponent._show = true; + fixtureComponent.code_sent = true; + fixtureComponent._authState = { + state: 'requireNewPassword', + user: {}, + }; + fixture.detectChanges(); + const a = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-link' + ); + a.click(); + expect(onSendSpy).toHaveBeenCalled(); + expect(forgotPasswordSpy).toHaveBeenCalled(); + }); + + it('...should call onSignIn when a tag is clicked and !codeSent', () => { + fixtureComponent._show = true; + fixtureComponent._authState = { + state: 'requireNewPassword', + user: {}, + }; + fixture.detectChanges(); + const a = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-link' + ); + a.click(); + expect(onSignInSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/forgot-password.component.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/forgot-password.component.ionic.spec.ts index 28268d7373b..49a15a30b6b 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/forgot-password.component.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/forgot-password.component.ionic.spec.ts @@ -1,125 +1,130 @@ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; -import { ForgotPasswordComponentIonic } -from '../../../components/authenticator/forgot-password-component/forgot-password.component.ionic'; - +import { ForgotPasswordComponentIonic } from '../../../components/authenticator/forgot-password-component/forgot-password.component.ionic'; describe('ForgotPasswordComponentIonic: ', () => { + let component: ForgotPasswordComponentIonic; + let fixtureComponent: ForgotPasswordComponentIonic; + let service: AmplifyService; + let fixture; + let onSubmitSpy; + let onSendSpy; + let forgotPasswordSpy; + let forgotPasswordSubmitSpy; + let onSignInSpy; - let component: ForgotPasswordComponentIonic; - let fixtureComponent: ForgotPasswordComponentIonic; - let service: AmplifyService; - let fixture; - let onSubmitSpy; - let onSendSpy; - let forgotPasswordSpy; - let forgotPasswordSubmitSpy; - let onSignInSpy; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new ForgotPasswordComponentIonic(service); - TestBed.configureTestingModule({ - declarations: [ - ForgotPasswordComponentIonic - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - }).compileComponents(); - fixture = TestBed.createComponent(ForgotPasswordComponentIonic); - fixtureComponent = fixture.componentInstance; - forgotPasswordSpy = jest.spyOn(service.auth(), 'forgotPassword'); - forgotPasswordSubmitSpy = jest.spyOn(service.auth(), 'forgotPasswordSubmit'); - onSubmitSpy = jest.spyOn(fixtureComponent, 'onSubmit'); - onSendSpy = jest.spyOn(fixtureComponent, 'onSend'); - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - }); + beforeEach(() => { + service = new AmplifyService(authModule); + component = new ForgotPasswordComponentIonic(service); + TestBed.configureTestingModule({ + declarations: [ForgotPasswordComponentIonic], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(ForgotPasswordComponentIonic); + fixtureComponent = fixture.componentInstance; + forgotPasswordSpy = jest.spyOn(service.auth(), 'forgotPassword'); + forgotPasswordSubmitSpy = jest.spyOn( + service.auth(), + 'forgotPasswordSubmit' + ); + onSubmitSpy = jest.spyOn(fixtureComponent, 'onSubmit'); + onSendSpy = jest.spyOn(fixtureComponent, 'onSend'); + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + }); - afterEach(() => { - service = null; - component = null; - }); + afterEach(() => { + service = null; + component = null; + }); + it('...should be created', () => { + expect(component).toBeTruthy(); + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); + it('...should have an onSend method', () => { + expect(component.onSend).toBeTruthy(); + }); - it('...should have an onSend method', () => { - expect(component.onSend).toBeTruthy(); - }); - - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); - it('...should have an onSubmit method', () => { - expect(component.onSubmit).toBeTruthy(); - }); + it('...should have an onSubmit method', () => { + expect(component.onSubmit).toBeTruthy(); + }); - it('...should have an setCode method', () => { - expect(component.setCode).toBeTruthy(); - }); + it('...should have an setCode method', () => { + expect(component.setCode).toBeTruthy(); + }); - it('...should have an _setError method', () => { - expect(component._setError).toBeTruthy(); - }); + it('...should have an _setError method', () => { + expect(component._setError).toBeTruthy(); + }); - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-authenticator-ionic'); - expect(rootEl).toBeFalsy(); - }); + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-authenticator-ionic' + ); + expect(rootEl).toBeFalsy(); + }); - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-authenticator-ionic'); - expect(rootEl).toBeTruthy(); - }); + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-authenticator-ionic' + ); + expect(rootEl).toBeTruthy(); + }); - it('...should call onSend when button is clicked and !codeSent', () => { - fixtureComponent._show = true; - fixtureComponent._authState = { - state: 'requireNewPassword', - user: {} - }; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('ion-button'); - button.click(); - expect(forgotPasswordSpy).not.toHaveBeenCalled(); - expect(onSendSpy).toHaveBeenCalled(); - fixtureComponent.username = 'username'; - fixture.detectChanges(); - button.click(); - expect(forgotPasswordSpy).toHaveBeenCalled(); - }); + it('...should call onSend when button is clicked and !codeSent', () => { + fixtureComponent._show = true; + fixtureComponent._authState = { + state: 'requireNewPassword', + user: {}, + }; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + 'ion-button' + ); + button.click(); + expect(forgotPasswordSpy).not.toHaveBeenCalled(); + expect(onSendSpy).toHaveBeenCalled(); + fixtureComponent.username = 'username'; + fixture.detectChanges(); + button.click(); + expect(forgotPasswordSpy).toHaveBeenCalled(); + }); - it('...should call onSubmit when button is clicked and codeSent', () => { - fixtureComponent._show = true; - fixtureComponent.code_sent = true; - fixtureComponent._authState = { - state: 'requireNewPassword', - user: {} - }; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('ion-button'); - button.click(); - expect(onSubmitSpy).toHaveBeenCalled(); - expect(forgotPasswordSubmitSpy).toHaveBeenCalled(); - }); + it('...should call onSubmit when button is clicked and codeSent', () => { + fixtureComponent._show = true; + fixtureComponent.code_sent = true; + fixtureComponent._authState = { + state: 'requireNewPassword', + user: {}, + }; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + 'ion-button' + ); + button.click(); + expect(onSubmitSpy).toHaveBeenCalled(); + expect(forgotPasswordSubmitSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/greetings.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/greetings.component.core.spec.ts index 5c6968ee66e..60e57f64d9a 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/greetings.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/greetings.component.core.spec.ts @@ -1,91 +1,90 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; -import { GreetingComponentCore } -from '../../../components/authenticator/greeting-component/greeting.component.core'; +import { GreetingComponentCore } from '../../../components/authenticator/greeting-component/greeting.component.core'; import { authModule } from '../../../__mocks__/mock_module'; describe('GreetingsComponentCore: ', () => { + let component: GreetingComponentCore; + let fixtureComponent: GreetingComponentCore; + let service: AmplifyService; + let fixture; + let onSignOutSpy; + let signOutSpy; - let component: GreetingComponentCore; - let fixtureComponent: GreetingComponentCore; - let service: AmplifyService; - let fixture; - let onSignOutSpy; - let signOutSpy; + beforeEach(() => { + service = new AmplifyService(authModule); + component = new GreetingComponentCore(service); + TestBed.configureTestingModule({ + declarations: [GreetingComponentCore], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(GreetingComponentCore); + fixtureComponent = fixture.componentInstance; + signOutSpy = jest.spyOn(service.auth(), 'signOut'); + onSignOutSpy = jest.spyOn(fixtureComponent, 'onSignOut'); + }); - beforeEach(() => { - service = new AmplifyService(authModule); - component = new GreetingComponentCore(service); - TestBed.configureTestingModule({ - declarations: [ - GreetingComponentCore - ], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - }).compileComponents(); - fixture = TestBed.createComponent(GreetingComponentCore); - fixtureComponent = fixture.componentInstance; - signOutSpy = jest.spyOn(service.auth(), 'signOut'); - onSignOutSpy = jest.spyOn(fixtureComponent, 'onSignOut'); - }); + afterEach(() => { + service = null; + component = null; + }); - afterEach(() => { - service = null; - component = null; - }); + it('...should be created', () => { + expect(component).toBeTruthy(); + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); + it('...should have an onSignOut method', () => { + expect(component.onSignOut).toBeTruthy(); + }); - it('...should have an onSignOut method', () => { - expect(component.onSignOut).toBeTruthy(); - }); + it('...should have a setAuthState method', () => { + expect(component.setAuthState).toBeTruthy(); + }); - it('...should have a setAuthState method', () => { - expect(component.setAuthState).toBeTruthy(); - }); + it('...should have a subscribe method', () => { + expect(component.subscribe).toBeTruthy(); + }); - it('...should have a subscribe method', () => { - expect(component.subscribe).toBeTruthy(); - }); + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-greeting' + ); + expect(rootEl).toBeFalsy(); + }); - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-greeting'); - expect(rootEl).toBeFalsy(); - }); - - it('...should display if _show is set', () => { - fixtureComponent.signedIn = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-greeting'); - expect(rootEl).toBeTruthy(); - }); - - it('...should call onSignOut when "a" tag is clicked', () => { - fixtureComponent.signedIn = true; - fixtureComponent.authState = { - state: 'signedIn', - user: {} - }; - fixture.detectChanges(); - const a = fixture.debugElement.nativeElement.querySelector('a'); - a.click(); - expect(onSignOutSpy).toHaveBeenCalled(); - expect(signOutSpy).toHaveBeenCalled(); - }); + it('...should display if _show is set', () => { + fixtureComponent.signedIn = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-greeting' + ); + expect(rootEl).toBeTruthy(); + }); + it('...should call onSignOut when "a" tag is clicked', () => { + fixtureComponent.signedIn = true; + fixtureComponent.authState = { + state: 'signedIn', + user: {}, + }; + fixture.detectChanges(); + const a = fixture.debugElement.nativeElement.querySelector('a'); + a.click(); + expect(onSignOutSpy).toHaveBeenCalled(); + expect(signOutSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/greetings.component.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/greetings.component.ionic.spec.ts index 878378c59b8..1623ebed861 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/greetings.component.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/greetings.component.ionic.spec.ts @@ -1,81 +1,78 @@ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; -import { GreetingComponentIonic } -from '../../../components/authenticator/greeting-component/greeting.component.ionic'; - +import { GreetingComponentIonic } from '../../../components/authenticator/greeting-component/greeting.component.ionic'; describe('GreetingsComponentCore: ', () => { + let component: GreetingComponentIonic; + let fixtureComponent: GreetingComponentIonic; + let service: AmplifyService; + let fixture; + let onSignOutSpy; + let signOutSpy; - let component: GreetingComponentIonic; - let fixtureComponent: GreetingComponentIonic; - let service: AmplifyService; - let fixture; - let onSignOutSpy; - let signOutSpy; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new GreetingComponentIonic(service); - TestBed.configureTestingModule({ - declarations: [ - GreetingComponentIonic - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - }).compileComponents(); - fixture = TestBed.createComponent(GreetingComponentIonic); - fixtureComponent = fixture.componentInstance; - signOutSpy = jest.spyOn(service.auth(), 'signOut'); - onSignOutSpy = jest.spyOn(fixtureComponent, 'onSignOut'); - }); - - afterEach(() => { - service = null; - component = null; - }); - + beforeEach(() => { + service = new AmplifyService(authModule); + component = new GreetingComponentIonic(service); + TestBed.configureTestingModule({ + declarations: [GreetingComponentIonic], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(GreetingComponentIonic); + fixtureComponent = fixture.componentInstance; + signOutSpy = jest.spyOn(service.auth(), 'signOut'); + onSignOutSpy = jest.spyOn(fixtureComponent, 'onSignOut'); + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); + afterEach(() => { + service = null; + component = null; + }); - it('...should have an onSignOut method', () => { - expect(component.onSignOut).toBeTruthy(); - }); + it('...should be created', () => { + expect(component).toBeTruthy(); + }); - it('...should have a setAuthState method', () => { - expect(component.setAuthState).toBeTruthy(); - }); + it('...should have an onSignOut method', () => { + expect(component.onSignOut).toBeTruthy(); + }); - it('...should have a subscribe method', () => { - expect(component.subscribe).toBeTruthy(); - }); + it('...should have a setAuthState method', () => { + expect(component.setAuthState).toBeTruthy(); + }); - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-greeting'); - expect(rootEl).toBeFalsy(); - }); + it('...should have a subscribe method', () => { + expect(component.subscribe).toBeTruthy(); + }); - it('...should display if _show is set', () => { - fixtureComponent.signedIn = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-greeting'); - expect(rootEl).toBeTruthy(); - }); + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-greeting' + ); + expect(rootEl).toBeFalsy(); + }); + it('...should display if _show is set', () => { + fixtureComponent.signedIn = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-greeting' + ); + expect(rootEl).toBeTruthy(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/phone-field.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/phone-field.component.core.spec.ts index 75a6fffda22..b14a966b8d6 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/phone-field.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/phone-field.component.core.spec.ts @@ -7,40 +7,38 @@ import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; describe('PhoneFieldComponentCore: ', () => { - let component: PhoneFieldComponentCore; - let fixtureComponent: PhoneFieldComponentCore; - let service: AmplifyService; - let fixture; + let component: PhoneFieldComponentCore; + let fixtureComponent: PhoneFieldComponentCore; + let service: AmplifyService; + let fixture; - beforeEach(() => { - service = new AmplifyService(authModule); - component = new PhoneFieldComponentCore(service); - TestBed.configureTestingModule({ - declarations: [ - PhoneFieldComponentCore - ], - imports: [FormsModule], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ] - }).compileComponents(); - fixture = TestBed.createComponent(PhoneFieldComponentCore); - fixtureComponent = fixture.componentInstance; - }); + beforeEach(() => { + service = new AmplifyService(authModule); + component = new PhoneFieldComponentCore(service); + TestBed.configureTestingModule({ + declarations: [PhoneFieldComponentCore], + imports: [FormsModule], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(PhoneFieldComponentCore); + fixtureComponent = fixture.componentInstance; + }); - afterEach(() => { - service = null; - component = null; - }); + afterEach(() => { + service = null; + component = null; + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); -}); \ No newline at end of file + it('...should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/phone-field.component.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/phone-field.component.ionic.spec.ts index 95af8abac6a..21488485a02 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/phone-field.component.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/phone-field.component.ionic.spec.ts @@ -6,40 +6,38 @@ import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; describe('PhoneFieldComponentIonic: ', () => { - let component: PhoneFieldComponentIonic; - let fixtureComponent: PhoneFieldComponentIonic; - let service: AmplifyService; - let fixture; + let component: PhoneFieldComponentIonic; + let fixtureComponent: PhoneFieldComponentIonic; + let service: AmplifyService; + let fixture; - beforeEach(() => { - service = new AmplifyService(authModule); - component = new PhoneFieldComponentIonic(service); - TestBed.configureTestingModule({ - declarations: [ - PhoneFieldComponentIonic - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ] - }).compileComponents(); - fixture = TestBed.createComponent(PhoneFieldComponentIonic); - fixtureComponent = fixture.componentInstance; - }); + beforeEach(() => { + service = new AmplifyService(authModule); + component = new PhoneFieldComponentIonic(service); + TestBed.configureTestingModule({ + declarations: [PhoneFieldComponentIonic], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(PhoneFieldComponentIonic); + fixtureComponent = fixture.componentInstance; + }); - afterEach(() => { - service = null; - component = null; - }); + afterEach(() => { + service = null; + component = null; + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); -}); \ No newline at end of file + it('...should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/require-new-password.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/require-new-password.component.core.spec.ts index a8939601e54..20a9b79bd0d 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/require-new-password.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/require-new-password.component.core.spec.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; @@ -11,96 +11,96 @@ import { RequireNewPasswordComponentCore } from '../../../components/authenticat // tslint:enable describe('RequireNewPasswordComponentCore: ', () => { + let component: RequireNewPasswordComponentCore; + let fixtureComponent: RequireNewPasswordComponentCore; + let service: AmplifyService; + let fixture; + let onSubmitSpy; + let completeNewPasswordSpy; + let onSignInSpy; - let component: RequireNewPasswordComponentCore; - let fixtureComponent: RequireNewPasswordComponentCore; - let service: AmplifyService; - let fixture; - let onSubmitSpy; - let completeNewPasswordSpy; - let onSignInSpy; + beforeEach(() => { + service = new AmplifyService(authModule); + component = new RequireNewPasswordComponentCore(service); + TestBed.configureTestingModule({ + declarations: [RequireNewPasswordComponentCore], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(RequireNewPasswordComponentCore); + fixtureComponent = fixture.componentInstance; + completeNewPasswordSpy = jest.spyOn(service.auth(), 'completeNewPassword'); + onSubmitSpy = jest.spyOn(fixtureComponent, 'onSubmit'); + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + }); - beforeEach(() => { - service = new AmplifyService(authModule); - component = new RequireNewPasswordComponentCore(service); - TestBed.configureTestingModule({ - declarations: [ - RequireNewPasswordComponentCore - ], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - }).compileComponents(); - fixture = TestBed.createComponent(RequireNewPasswordComponentCore); - fixtureComponent = fixture.componentInstance; - completeNewPasswordSpy = jest.spyOn(service.auth(), 'completeNewPassword'); - onSubmitSpy = jest.spyOn(fixtureComponent, 'onSubmit'); - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - }); + afterEach(() => { + service = null; + component = null; + }); - afterEach(() => { - service = null; - component = null; - }); + it('...should be created', () => { + expect(component).toBeTruthy(); + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); + it('...should have an onSubmit method', () => { + expect(component.onSubmit).toBeTruthy(); + }); - it('...should have an onSubmit method', () => { - expect(component.onSubmit).toBeTruthy(); - }); + it('...should have a setPassword method', () => { + expect(component.setPassword).toBeTruthy(); + }); - it('...should have a setPassword method', () => { - expect(component.setPassword).toBeTruthy(); - }); + it('...should have a _setError method', () => { + expect(component._setError).toBeTruthy(); + }); - it('...should have a _setError method', () => { - expect(component._setError).toBeTruthy(); - }); + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeFalsy(); + }); - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeFalsy(); - }); + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeTruthy(); + }); - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeTruthy(); - }); - - it('...should call onSubmit when button is clicked', () => { - fixtureComponent._show = true; - fixtureComponent.authState = { - state: 'requireNewPassword', - user: { challengeParam: {} } - }; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('button'); - button.click(); - expect(onSubmitSpy).toHaveBeenCalled(); - expect(completeNewPasswordSpy).toHaveBeenCalled(); - }); - - it('...should call onSignIn when "a" tag is clicked', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const a = fixture.debugElement.nativeElement.querySelector('a'); - a.click(); - expect(onSignInSpy).toHaveBeenCalled(); - }); + it('...should call onSubmit when button is clicked', () => { + fixtureComponent._show = true; + fixtureComponent.authState = { + state: 'requireNewPassword', + user: { challengeParam: {} }, + }; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector('button'); + button.click(); + expect(onSubmitSpy).toHaveBeenCalled(); + expect(completeNewPasswordSpy).toHaveBeenCalled(); + }); + it('...should call onSignIn when "a" tag is clicked', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const a = fixture.debugElement.nativeElement.querySelector('a'); + a.click(); + expect(onSignInSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/require-new-password.component.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/require-new-password.component.ionic.spec.ts index a363e739dd6..63bc4a939ab 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/require-new-password.component.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/require-new-password.component.ionic.spec.ts @@ -1,8 +1,8 @@ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; @@ -11,106 +11,110 @@ import { RequireNewPasswordComponentIonic } from '../../../components/authentica // tslint:enable describe('RequireNewPasswordComponentCore: ', () => { + let component: RequireNewPasswordComponentIonic; + let fixtureComponent: RequireNewPasswordComponentIonic; + let service: AmplifyService; + let fixture; + let onSubmitSpy; + let completeNewPasswordSpy; + let onSignInSpy; - let component: RequireNewPasswordComponentIonic; - let fixtureComponent: RequireNewPasswordComponentIonic; - let service: AmplifyService; - let fixture; - let onSubmitSpy; - let completeNewPasswordSpy; - let onSignInSpy; + beforeEach(() => { + service = new AmplifyService(authModule); + component = new RequireNewPasswordComponentIonic(service); + TestBed.configureTestingModule({ + declarations: [RequireNewPasswordComponentIonic], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(RequireNewPasswordComponentIonic); + fixtureComponent = fixture.componentInstance; + completeNewPasswordSpy = jest.spyOn(service.auth(), 'completeNewPassword'); + onSubmitSpy = jest.spyOn(fixtureComponent, 'onSubmit'); + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + }); - beforeEach(() => { - service = new AmplifyService(authModule); - component = new RequireNewPasswordComponentIonic(service); - TestBed.configureTestingModule({ - declarations: [ - RequireNewPasswordComponentIonic - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - }).compileComponents(); - fixture = TestBed.createComponent(RequireNewPasswordComponentIonic); - fixtureComponent = fixture.componentInstance; - completeNewPasswordSpy = jest.spyOn(service.auth(), 'completeNewPassword'); - onSubmitSpy = jest.spyOn(fixtureComponent, 'onSubmit'); - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - }); + afterEach(() => { + service = null; + component = null; + }); - afterEach(() => { - service = null; - component = null; - }); + it('...should be created', () => { + expect(component).toBeTruthy(); + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); + it('...should have an onSubmit method', () => { + expect(component.onSubmit).toBeTruthy(); + }); - it('...should have an onSubmit method', () => { - expect(component.onSubmit).toBeTruthy(); - }); + it('...should have a setPassword method', () => { + expect(component.setPassword).toBeTruthy(); + }); - it('...should have a setPassword method', () => { - expect(component.setPassword).toBeTruthy(); - }); + it('...should have a _setError method', () => { + expect(component._setError).toBeTruthy(); + }); - it('...should have a _setError method', () => { - expect(component._setError).toBeTruthy(); - }); + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-authenticator-ionic' + ); + expect(rootEl).toBeFalsy(); + }); - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-authenticator-ionic'); - expect(rootEl).toBeFalsy(); - }); + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-authenticator-ionic' + ); + expect(rootEl).toBeTruthy(); + }); - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-authenticator-ionic'); - expect(rootEl).toBeTruthy(); - }); - - it('...should call onSignIn when button is clicked', () => { - fixtureComponent._show = true; - fixtureComponent.authState = { - state: 'requireNewPassword', - user: { challengeParam: {} } - }; - fixture.detectChanges(); - const buttons = fixture.debugElement.nativeElement - .querySelectorAll('ion-button'); - const signInButton = Object.values(buttons) - .find((el) => el.innerHTML === 'Back to Sign In'); - signInButton.click(); - expect(onSignInSpy).toHaveBeenCalled(); - }); - - it('...should call onSubmit when button is clicked', () => { - fixtureComponent._show = true; - fixtureComponent.authState = { - state: 'requireNewPassword', - user: { challengeParam: {} } - }; - fixture.detectChanges(); - const buttons = fixture.debugElement.nativeElement - .querySelectorAll('ion-button'); - const submitButton = Object.values(buttons) - .find((el) => el.innerHTML === 'Submit'); - submitButton.click(); - expect(onSubmitSpy).toHaveBeenCalled(); - }); + it('...should call onSignIn when button is clicked', () => { + fixtureComponent._show = true; + fixtureComponent.authState = { + state: 'requireNewPassword', + user: { challengeParam: {} }, + }; + fixture.detectChanges(); + const buttons = fixture.debugElement.nativeElement.querySelectorAll( + 'ion-button' + ); + const signInButton = Object.values(buttons).find( + el => el.innerHTML === 'Back to Sign In' + ); + signInButton.click(); + expect(onSignInSpy).toHaveBeenCalled(); + }); + it('...should call onSubmit when button is clicked', () => { + fixtureComponent._show = true; + fixtureComponent.authState = { + state: 'requireNewPassword', + user: { challengeParam: {} }, + }; + fixture.detectChanges(); + const buttons = fixture.debugElement.nativeElement.querySelectorAll( + 'ion-button' + ); + const submitButton = Object.values(buttons).find( + el => el.innerHTML === 'Submit' + ); + submitButton.click(); + expect(onSubmitSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-in.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-in.component.core.spec.ts index 4273297544b..b3388c52e50 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-in.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-in.component.core.spec.ts @@ -3,8 +3,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { MockComponent } from 'ng-mocks'; import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; @@ -12,141 +12,149 @@ import { SignInComponentCore } from '../../../components/authenticator/sign-in-c import { UsernameFieldComponentCore } from '../../../components/authenticator/username-field-component/username-field.component.core'; describe('SignInComponentCore: ', () => { - - let component: SignInComponentCore; - let fixtureComponent: SignInComponentCore; - let service: AmplifyService; - let fixture; - let setAuthStateSpy; - let signInSpy; - let onSignInSpy; - let onSignUpSpy; - let onForgotPasswordSpy; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new SignInComponentCore(service); - TestBed.configureTestingModule({ - declarations: [ - SignInComponentCore, - MockComponent(UsernameFieldComponentCore) - ], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - imports: [FormsModule] - }).compileComponents(); - fixture = TestBed.createComponent(SignInComponentCore); - fixtureComponent = fixture.componentInstance; - setAuthStateSpy = jest.spyOn(service, 'setAuthState'); - signInSpy = jest.spyOn(service.auth(), 'signIn'); - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - onSignUpSpy = jest.spyOn(fixtureComponent, 'onSignUp'); - onForgotPasswordSpy = jest.spyOn(fixtureComponent, 'onForgotPassword'); - }); - - afterEach(() => { - service = null; - component = null; - }); - - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have an onForgotPassword method', () => { - expect(component.onForgotPassword).toBeTruthy(); - }); - - it('...should call setAuthState within the onForgotPassword method', () => { - component.username = 'test-username2'; - const callingAuthState = component.onForgotPassword(); - expect(service.setAuthState).toBeCalled(); - }); - - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); - - it('...should call signIn within the onSignUp method', () => { - component.username = 'test-username3'; - component.password = 'test-password3'; - const callingAuthState = component.onSignIn(); - expect(signInSpy).toBeCalled(); - }); - - it('...should have an onSignUp method', () => { - expect(component.onSignUp).toBeTruthy(); - }); - - it('...should call setAuthState within the onSignUp method', () => { - component.username = 'test-username2'; - const callingAuthState = component.onSignUp(); - expect(service.setAuthState).toBeCalled(); - }); - - it('...should have a setPassword method', () => { - expect(component.setPassword).toBeTruthy(); - }); - - it('...should set this.password with the setPassword method', () => { - component.setPassword('my-test-password'); - expect(component.password).toEqual('my-test-password'); - }); - - it('...should have a setUsername method', () => { - expect(component.setUsername).toBeTruthy(); - }); - - it('...should set this.username with the setUsername method', () => { - component.setUsername('my-test-name'); - expect(component.username).toEqual('my-test-name'); - }); - - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeFalsy(); - }); - - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeTruthy(); - }); - - it('...should call onSignIn when button is clicked', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('.amplify-form-button'); - button.click(); - expect(onSignInSpy).toHaveBeenCalled(); - expect(signInSpy).toHaveBeenCalled(); - }); - - it('...should call onSignUp when "No account?" element is clicked', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const parent = fixture.debugElement.nativeElement.querySelector('.amplify-form-signup'); - const a = parent.querySelector('.amplify-form-link'); - a.click(); - expect(onSignUpSpy).toHaveBeenCalled(); - }); - - it('...should call onForgotPassword when "Forgot password?" element is clicked', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const parent = fixture.debugElement.nativeElement.querySelector('.amplify-form-action'); - const a = parent.querySelector('.amplify-form-link'); - a.click(); - expect(onForgotPasswordSpy).toHaveBeenCalled(); - }); + let component: SignInComponentCore; + let fixtureComponent: SignInComponentCore; + let service: AmplifyService; + let fixture; + let setAuthStateSpy; + let signInSpy; + let onSignInSpy; + let onSignUpSpy; + let onForgotPasswordSpy; + + beforeEach(() => { + service = new AmplifyService(authModule); + component = new SignInComponentCore(service); + TestBed.configureTestingModule({ + declarations: [ + SignInComponentCore, + MockComponent(UsernameFieldComponentCore), + ], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + imports: [FormsModule], + }).compileComponents(); + fixture = TestBed.createComponent(SignInComponentCore); + fixtureComponent = fixture.componentInstance; + setAuthStateSpy = jest.spyOn(service, 'setAuthState'); + signInSpy = jest.spyOn(service.auth(), 'signIn'); + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + onSignUpSpy = jest.spyOn(fixtureComponent, 'onSignUp'); + onForgotPasswordSpy = jest.spyOn(fixtureComponent, 'onForgotPassword'); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have an onForgotPassword method', () => { + expect(component.onForgotPassword).toBeTruthy(); + }); + + it('...should call setAuthState within the onForgotPassword method', () => { + component.username = 'test-username2'; + const callingAuthState = component.onForgotPassword(); + expect(service.setAuthState).toBeCalled(); + }); + + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); + + it('...should call signIn within the onSignUp method', () => { + component.username = 'test-username3'; + component.password = 'test-password3'; + const callingAuthState = component.onSignIn(); + expect(signInSpy).toBeCalled(); + }); + + it('...should have an onSignUp method', () => { + expect(component.onSignUp).toBeTruthy(); + }); + + it('...should call setAuthState within the onSignUp method', () => { + component.username = 'test-username2'; + const callingAuthState = component.onSignUp(); + expect(service.setAuthState).toBeCalled(); + }); + + it('...should have a setPassword method', () => { + expect(component.setPassword).toBeTruthy(); + }); + + it('...should set this.password with the setPassword method', () => { + component.setPassword('my-test-password'); + expect(component.password).toEqual('my-test-password'); + }); + + it('...should have a setUsername method', () => { + expect(component.setUsername).toBeTruthy(); + }); + + it('...should set this.username with the setUsername method', () => { + component.setUsername('my-test-name'); + expect(component.username).toEqual('my-test-name'); + }); + + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeFalsy(); + }); + + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeTruthy(); + }); + + it('...should call onSignIn when button is clicked', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-button' + ); + button.click(); + expect(onSignInSpy).toHaveBeenCalled(); + expect(signInSpy).toHaveBeenCalled(); + }); + + it('...should call onSignUp when "No account?" element is clicked', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const parent = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-signup' + ); + const a = parent.querySelector('.amplify-form-link'); + a.click(); + expect(onSignUpSpy).toHaveBeenCalled(); + }); + + it('...should call onForgotPassword when "Forgot password?" element is clicked', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const parent = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-action' + ); + const a = parent.querySelector('.amplify-form-link'); + a.click(); + expect(onForgotPasswordSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-in.component.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-in.component.ionic.spec.ts index da6f8254593..73a9244db51 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-in.component.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-in.component.ionic.spec.ts @@ -1,144 +1,146 @@ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { - BrowserDynamicTestingModule,platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; -import { SignInComponentIonic } -from '../../../components/authenticator/sign-in-component/sign-in.component.ionic'; +import { SignInComponentIonic } from '../../../components/authenticator/sign-in-component/sign-in.component.ionic'; import Amplify from 'aws-amplify'; - describe('SignInComponentIonic: ', () => { - - let component: SignInComponentIonic; - let fixtureComponent: SignInComponentIonic; - let fixture; - let service: AmplifyService; - let setAuthStateSpy; - let signInSpy; - let onSignInSpy; - let onSignUpSpy; - let onForgotPasswordSpy; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new SignInComponentIonic(service); - setAuthStateSpy = jest.spyOn(service, 'setAuthState'); - signInSpy = jest.spyOn(service.auth(), 'signIn'); - TestBed.configureTestingModule({ - declarations: [ - SignInComponentIonic - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - }).compileComponents(); - fixture = TestBed.createComponent(SignInComponentIonic); - fixtureComponent = fixture.componentInstance; - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - onSignUpSpy = jest.spyOn(fixtureComponent, 'onSignUp'); - onForgotPasswordSpy = jest.spyOn(fixtureComponent, 'onForgotPassword'); - }); - - afterEach(() => { - service = null; - component = null; - }); - - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have an onForgotPassword method', () => { - expect(component.onForgotPassword).toBeTruthy(); - }); - - it('...should call setAuthState within the onForgotPassword method', () => { - component.username = 'test-username2'; - const callingAuthState = component.onForgotPassword(); - expect(service.setAuthState).toBeCalled(); - setAuthStateSpy.mockRestore(); - }); - - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); - - it('...should call signIn within the onSignUp method', () => { - component.username = 'test-username3'; - component.password = 'test-password3'; - const callingAuthState = component.onSignIn(); - expect(signInSpy).toBeCalled(); - }); - - it('...should have an onSignUp method', () => { - expect(component.onSignUp).toBeTruthy(); - }); - - it('...should call setAuthState within the onSignUp method', () => { - component.username = 'test-username2'; - const callingAuthState = component.onSignUp(); - expect(service.setAuthState).toBeCalled(); - setAuthStateSpy.mockRestore(); - }); - - it('...should have a setPassword method', () => { - expect(component.setPassword).toBeTruthy(); - }); - - it('...should set this.password with the setPassword method', () => { - component.setPassword('my-test-password'); - expect(component.password).toEqual('my-test-password'); - }); - - it('...should have a setUsername method', () => { - expect(component.setUsername).toBeTruthy(); - }); - - it('...should set this.username with the setUsername method', () => { - component.setUsername('my-test-name'); - expect(component.username).toEqual('my-test-name'); - }); - - - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-authenticator'); - expect(rootEl).toBeFalsy(); - }); - - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-authenticator'); - expect(rootEl).toBeTruthy(); - }); - - it('...should call onSignIn when button is clicked', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('ion-button'); - button.click(); - expect(onSignInSpy).toHaveBeenCalled(); - expect(signInSpy).toHaveBeenCalled(); - }); - - it('...should call onSignUp when "No account?" element is clicked', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const parent = fixture.debugElement.nativeElement.querySelector('.amplify-form-signup'); - const a = parent.querySelector('.amplify-form-link'); - a.click(); - expect(onSignUpSpy).toHaveBeenCalled(); - }); + let component: SignInComponentIonic; + let fixtureComponent: SignInComponentIonic; + let fixture; + let service: AmplifyService; + let setAuthStateSpy; + let signInSpy; + let onSignInSpy; + let onSignUpSpy; + let onForgotPasswordSpy; + + beforeEach(() => { + service = new AmplifyService(authModule); + component = new SignInComponentIonic(service); + setAuthStateSpy = jest.spyOn(service, 'setAuthState'); + signInSpy = jest.spyOn(service.auth(), 'signIn'); + TestBed.configureTestingModule({ + declarations: [SignInComponentIonic], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(SignInComponentIonic); + fixtureComponent = fixture.componentInstance; + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + onSignUpSpy = jest.spyOn(fixtureComponent, 'onSignUp'); + onForgotPasswordSpy = jest.spyOn(fixtureComponent, 'onForgotPassword'); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have an onForgotPassword method', () => { + expect(component.onForgotPassword).toBeTruthy(); + }); + + it('...should call setAuthState within the onForgotPassword method', () => { + component.username = 'test-username2'; + const callingAuthState = component.onForgotPassword(); + expect(service.setAuthState).toBeCalled(); + setAuthStateSpy.mockRestore(); + }); + + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); + + it('...should call signIn within the onSignUp method', () => { + component.username = 'test-username3'; + component.password = 'test-password3'; + const callingAuthState = component.onSignIn(); + expect(signInSpy).toBeCalled(); + }); + + it('...should have an onSignUp method', () => { + expect(component.onSignUp).toBeTruthy(); + }); + + it('...should call setAuthState within the onSignUp method', () => { + component.username = 'test-username2'; + const callingAuthState = component.onSignUp(); + expect(service.setAuthState).toBeCalled(); + setAuthStateSpy.mockRestore(); + }); + + it('...should have a setPassword method', () => { + expect(component.setPassword).toBeTruthy(); + }); + + it('...should set this.password with the setPassword method', () => { + component.setPassword('my-test-password'); + expect(component.password).toEqual('my-test-password'); + }); + + it('...should have a setUsername method', () => { + expect(component.setUsername).toBeTruthy(); + }); + + it('...should set this.username with the setUsername method', () => { + component.setUsername('my-test-name'); + expect(component.username).toEqual('my-test-name'); + }); + + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-authenticator' + ); + expect(rootEl).toBeFalsy(); + }); + + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-authenticator' + ); + expect(rootEl).toBeTruthy(); + }); + + it('...should call onSignIn when button is clicked', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + 'ion-button' + ); + button.click(); + expect(onSignInSpy).toHaveBeenCalled(); + expect(signInSpy).toHaveBeenCalled(); + }); + + it('...should call onSignUp when "No account?" element is clicked', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const parent = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-signup' + ); + const a = parent.querySelector('.amplify-form-link'); + a.click(); + expect(onSignUpSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-up.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-up.component.core.spec.ts index 4f30a14233c..700c2a53ff3 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-up.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-up.component.core.spec.ts @@ -4,240 +4,250 @@ import { FormsModule } from '@angular/forms'; import { MockComponent } from 'ng-mocks'; import { By } from '@angular/platform-browser'; import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { authModule } from '../../../__mocks__/mock_module'; -import { - SignUpComponentCore, - SignUpField +import { + SignUpComponentCore, + SignUpField, } from '../../../components/authenticator/sign-up-component/sign-up.component.core'; import { PhoneFieldComponentCore } from '../../../components/authenticator/phone-field-component/phone-field.component.core'; // tslint:enable describe('SignUpComponentCore (basics): ', () => { - - let component: SignUpComponentCore; - let service: AmplifyService; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new SignUpComponentCore(service); - }); - - afterEach(() => { - service = null; - component = null; - }); - - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have an onConfirmSignUp method', () => { - expect(component.onConfirmSignUp).toBeTruthy(); - }); - - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); - - it('...should have an onSignUp method', () => { - expect(component.onSignUp).toBeTruthy(); - }); - - it('...should have an sortFields method', () => { - expect(component.sortFields).toBeTruthy(); - }); - + let component: SignUpComponentCore; + let service: AmplifyService; + + beforeEach(() => { + service = new AmplifyService(authModule); + component = new SignUpComponentCore(service); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have an onConfirmSignUp method', () => { + expect(component.onConfirmSignUp).toBeTruthy(); + }); + + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); + + it('...should have an onSignUp method', () => { + expect(component.onSignUp).toBeTruthy(); + }); + + it('...should have an sortFields method', () => { + expect(component.sortFields).toBeTruthy(); + }); }); describe('SignUpComponentCore (methods and UI): ', () => { - - let component: SignUpComponentCore; - let fixture: ComponentFixture; - let service; - let fixtureComponent: SignUpComponentCore; - let amplifyService: AmplifyService; - let onSignUpSpy; - let signUpSpy; - let onSignInSpy; - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ - SignUpComponentCore, - MockComponent(PhoneFieldComponentCore) - ], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - imports: [FormsModule] - }).compileComponents(); - service = new AmplifyService(authModule); - fixture = TestBed.createComponent(SignUpComponentCore); - fixtureComponent = fixture.componentInstance; - component = fixture.componentInstance; - amplifyService = TestBed.get(AmplifyService); - onSignUpSpy = jest.spyOn(fixtureComponent, 'onSignUp'); - signUpSpy = jest.spyOn(service.auth(), 'signUp'); - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - }); - - afterEach(() => { - component.signUpConfig = undefined; - }); - - it('...should be created with 4 default signUpFields', () => { - expect(component.signUpFields.length).toBe(4); - expect(component.signUpFields.find(e => e.key === 'username')).toBeTruthy(); - expect(component.signUpFields.find(e => e.key === 'password')).toBeTruthy(); - expect(component.signUpFields.find(e => e.key === 'email')).toBeTruthy(); - expect(component.signUpFields.find(e => e.key === 'phone_number')).toBeTruthy(); - }); - - describe('...with component ngOnInit...', () => { - beforeEach(async() => { - component.signUpConfig = { - signUpFields: [ - { - key: 'testkey', - label: 'testlabel' - } - ] - }; - component.ngOnInit(); - await fixture.whenStable(); - }); - it('...should insert fields passed via signUpConfig', () => { - - expect(component.signUpFields.length).toBe(5); - expect(component.signUpFields.find(e => e.key === 'username')).toBeTruthy(); - expect(component.signUpFields.find(e => e.key === 'password')).toBeTruthy(); - expect(component.signUpFields.find(e => e.key === 'email')).toBeTruthy(); - expect(component.signUpFields.find(e => e.key === 'phone_number')).toBeTruthy(); - expect(component.signUpFields.find(e => e.key === 'testkey')).toBeTruthy(); - }); - }); - - describe('...with component ngOnInit...', () => { - beforeEach(async() => { - component.signUpConfig = { - signUpFields: [ - { - key: 'testkey', - label: 'testlabel' - } - ] - }; - component.ngOnInit(); - await fixture.whenStable(); - }); - it('...should insert only passed fields when hideDefaults is true', () => { - component.signUpConfig = { - hideDefaults: true, - signUpFields: [ - { - key: 'testkey', - label: 'testlabel' - } - ] - }; - expect(component.signUpFields.length).toBe(1); - }); - }); - - describe('...with component ngOnInit...', () => { - beforeEach(async() => { - component.signUpConfig = { - hiddenDefaults: ['email'], - }; - component.ngOnInit(); - await fixture.whenStable(); - }); - it('...should exclude hiddentDefaults', () => { - expect(component.defaultSignUpFields.length).toBe(3); - }); - }); - - describe('...with component ngOnInit...', () => { - beforeEach(async() => { - component.signUpConfig = { - signUpFields: [ - { - key: 'testkey1', - label: 'testlabel1', - displayOrder: 6 - }, - { - key: 'testkey2', - label: 'testlabel2', - displayOrder: 5 - } - ] - }; - component.ngOnInit(); - await fixture.whenStable(); - }); - it('...should order fields by display order', () => { - expect(component.signUpFields[5].key).toBe('testkey1'); - expect(component.signUpFields[4].key).toBe('testkey2'); - }); - }); - - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeFalsy(); - }); - - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-container'); - expect(rootEl).toBeTruthy(); - }); - - // tslint:disable:max-line-length - it('...should call onSignUp when button is clicked (but signUp will not be called if validation does not pass)', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('button'); - button.click(); - expect(onSignUpSpy).toHaveBeenCalled(); - expect(signUpSpy).not.toHaveBeenCalled(); - }); - - it('...should call onSignUp when button is clicked and signUp will be called since validation passes', () => { - fixtureComponent._show = true; - fixtureComponent.user = { - username: 'testusername', - password: 'testpassword', - email: 'testemail' - }; - fixtureComponent.country_code = '1'; - fixtureComponent.local_phone_number ='123'; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('button'); - button.click(); - expect(onSignUpSpy).toHaveBeenCalled(); - expect(signUpSpy).toHaveBeenCalled(); - }); - - it('...should call onSignIn when "amplify-form-link" is clicked', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const a = fixture.debugElement.nativeElement.querySelector('.amplify-form-link'); - a.click(); - expect(onSignInSpy).toHaveBeenCalled(); - }); + let component: SignUpComponentCore; + let fixture: ComponentFixture; + let service; + let fixtureComponent: SignUpComponentCore; + let amplifyService: AmplifyService; + let onSignUpSpy; + let signUpSpy; + let onSignInSpy; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + SignUpComponentCore, + MockComponent(PhoneFieldComponentCore), + ], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + imports: [FormsModule], + }).compileComponents(); + service = new AmplifyService(authModule); + fixture = TestBed.createComponent(SignUpComponentCore); + fixtureComponent = fixture.componentInstance; + component = fixture.componentInstance; + amplifyService = TestBed.get(AmplifyService); + onSignUpSpy = jest.spyOn(fixtureComponent, 'onSignUp'); + signUpSpy = jest.spyOn(service.auth(), 'signUp'); + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + }); + + afterEach(() => { + component.signUpConfig = undefined; + }); + + it('...should be created with 4 default signUpFields', () => { + expect(component.signUpFields.length).toBe(4); + expect(component.signUpFields.find(e => e.key === 'username')).toBeTruthy(); + expect(component.signUpFields.find(e => e.key === 'password')).toBeTruthy(); + expect(component.signUpFields.find(e => e.key === 'email')).toBeTruthy(); + expect( + component.signUpFields.find(e => e.key === 'phone_number') + ).toBeTruthy(); + }); + + describe('...with component ngOnInit...', () => { + beforeEach(async () => { + component.signUpConfig = { + signUpFields: [ + { + key: 'testkey', + label: 'testlabel', + }, + ], + }; + component.ngOnInit(); + await fixture.whenStable(); + }); + it('...should insert fields passed via signUpConfig', () => { + expect(component.signUpFields.length).toBe(5); + expect( + component.signUpFields.find(e => e.key === 'username') + ).toBeTruthy(); + expect( + component.signUpFields.find(e => e.key === 'password') + ).toBeTruthy(); + expect(component.signUpFields.find(e => e.key === 'email')).toBeTruthy(); + expect( + component.signUpFields.find(e => e.key === 'phone_number') + ).toBeTruthy(); + expect( + component.signUpFields.find(e => e.key === 'testkey') + ).toBeTruthy(); + }); + }); + + describe('...with component ngOnInit...', () => { + beforeEach(async () => { + component.signUpConfig = { + signUpFields: [ + { + key: 'testkey', + label: 'testlabel', + }, + ], + }; + component.ngOnInit(); + await fixture.whenStable(); + }); + it('...should insert only passed fields when hideDefaults is true', () => { + component.signUpConfig = { + hideDefaults: true, + signUpFields: [ + { + key: 'testkey', + label: 'testlabel', + }, + ], + }; + expect(component.signUpFields.length).toBe(1); + }); + }); + + describe('...with component ngOnInit...', () => { + beforeEach(async () => { + component.signUpConfig = { + hiddenDefaults: ['email'], + }; + component.ngOnInit(); + await fixture.whenStable(); + }); + it('...should exclude hiddentDefaults', () => { + expect(component.defaultSignUpFields.length).toBe(3); + }); + }); + + describe('...with component ngOnInit...', () => { + beforeEach(async () => { + component.signUpConfig = { + signUpFields: [ + { + key: 'testkey1', + label: 'testlabel1', + displayOrder: 6, + }, + { + key: 'testkey2', + label: 'testlabel2', + displayOrder: 5, + }, + ], + }; + component.ngOnInit(); + await fixture.whenStable(); + }); + it('...should order fields by display order', () => { + expect(component.signUpFields[5].key).toBe('testkey1'); + expect(component.signUpFields[4].key).toBe('testkey2'); + }); + }); + + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeFalsy(); + }); + + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-container' + ); + expect(rootEl).toBeTruthy(); + }); + + // tslint:disable:max-line-length + it('...should call onSignUp when button is clicked (but signUp will not be called if validation does not pass)', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector('button'); + button.click(); + expect(onSignUpSpy).toHaveBeenCalled(); + expect(signUpSpy).not.toHaveBeenCalled(); + }); + + it('...should call onSignUp when button is clicked and signUp will be called since validation passes', () => { + fixtureComponent._show = true; + fixtureComponent.user = { + username: 'testusername', + password: 'testpassword', + email: 'testemail', + }; + fixtureComponent.country_code = '1'; + fixtureComponent.local_phone_number = '123'; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector('button'); + button.click(); + expect(onSignUpSpy).toHaveBeenCalled(); + expect(signUpSpy).toHaveBeenCalled(); + }); + + it('...should call onSignIn when "amplify-form-link" is clicked', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const a = fixture.debugElement.nativeElement.querySelector( + '.amplify-form-link' + ); + a.click(); + expect(onSignInSpy).toHaveBeenCalled(); + }); }); - diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-up.component.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-up.component.ionic.spec.ts index 411fd4473a5..2a26fef44f0 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-up.component.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/sign-up.component.ionic.spec.ts @@ -1,108 +1,112 @@ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService, AmplifyModules } from '../../../providers'; import { FormsModule } from '@angular/forms'; import { authModule } from '../../../__mocks__/mock_module'; -import { SignUpComponentIonic } -from '../../../components/authenticator/sign-up-component/sign-up.component.ionic'; - +import { SignUpComponentIonic } from '../../../components/authenticator/sign-up-component/sign-up.component.ionic'; describe('SignUpComponentCore: ', () => { + let component: SignUpComponentIonic; + let fixtureComponent: SignUpComponentIonic; + let service: AmplifyService; + let fixture; + let onSignUpSpy; + let signUpSpy; + let onSignInSpy; - let component: SignUpComponentIonic; - let fixtureComponent: SignUpComponentIonic; - let service: AmplifyService; - let fixture; - let onSignUpSpy; - let signUpSpy; - let onSignInSpy; - - beforeEach(() => { - service = new AmplifyService(authModule); - component = new SignUpComponentIonic(service); - TestBed.configureTestingModule({ - declarations: [SignUpComponentIonic], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ], - }).compileComponents(); - fixture = TestBed.createComponent(SignUpComponentIonic); - fixtureComponent = fixture.componentInstance; - onSignUpSpy = jest.spyOn(fixtureComponent, 'onSignUp'); - signUpSpy = jest.spyOn(service.auth(), 'signUp'); - onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); - }); - - afterEach(() => { - service = null; - component = null; - }); + beforeEach(() => { + service = new AmplifyService(authModule); + component = new SignUpComponentIonic(service); + TestBed.configureTestingModule({ + declarations: [SignUpComponentIonic], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(SignUpComponentIonic); + fixtureComponent = fixture.componentInstance; + onSignUpSpy = jest.spyOn(fixtureComponent, 'onSignUp'); + signUpSpy = jest.spyOn(service.auth(), 'signUp'); + onSignInSpy = jest.spyOn(fixtureComponent, 'onSignIn'); + }); + afterEach(() => { + service = null; + component = null; + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); + it('...should be created', () => { + expect(component).toBeTruthy(); + }); - it('...should have an onConfirmSignUp method', () => { - expect(component.onConfirmSignUp).toBeTruthy(); - }); + it('...should have an onConfirmSignUp method', () => { + expect(component.onConfirmSignUp).toBeTruthy(); + }); - it('...should have an onSignIn method', () => { - expect(component.onSignIn).toBeTruthy(); - }); + it('...should have an onSignIn method', () => { + expect(component.onSignIn).toBeTruthy(); + }); - it('...should have an onSignUp method', () => { - expect(component.onSignUp).toBeTruthy(); - }); + it('...should have an onSignUp method', () => { + expect(component.onSignUp).toBeTruthy(); + }); - it('...should not display if _show is not set', () => { - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-authenticator'); - expect(rootEl).toBeFalsy(); - }); + it('...should not display if _show is not set', () => { + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-authenticator' + ); + expect(rootEl).toBeFalsy(); + }); - it('...should display if _show is set', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const rootEl = fixture.debugElement.nativeElement.querySelector('.amplify-authenticator'); - expect(rootEl).toBeTruthy(); - }); + it('...should display if _show is set', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const rootEl = fixture.debugElement.nativeElement.querySelector( + '.amplify-authenticator' + ); + expect(rootEl).toBeTruthy(); + }); - // tslint:disable:max-line-length - it('...should call onSignUp when button is clicked (but signUp will not be called if validation does not pass)', () => { - fixtureComponent._show = true; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('ion-button'); - button.click(); - expect(onSignUpSpy).toHaveBeenCalled(); - expect(signUpSpy).not.toHaveBeenCalled(); - }); + // tslint:disable:max-line-length + it('...should call onSignUp when button is clicked (but signUp will not be called if validation does not pass)', () => { + fixtureComponent._show = true; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + 'ion-button' + ); + button.click(); + expect(onSignUpSpy).toHaveBeenCalled(); + expect(signUpSpy).not.toHaveBeenCalled(); + }); - it('...should call onSignUp when button is clicked and signUp will be called since validation passes', () => { - fixtureComponent._show = true; - fixtureComponent.user = { - username: 'testusername', - password: 'testpassword', - email: 'testemail' - }; - fixtureComponent.country_code = '1'; - fixtureComponent.local_phone_number ='123'; - fixture.detectChanges(); - const button = fixture.debugElement.nativeElement.querySelector('ion-button'); - button.click(); - expect(onSignUpSpy).toHaveBeenCalled(); - expect(signUpSpy).toHaveBeenCalled(); - }); + it('...should call onSignUp when button is clicked and signUp will be called since validation passes', () => { + fixtureComponent._show = true; + fixtureComponent.user = { + username: 'testusername', + password: 'testpassword', + email: 'testemail', + }; + fixtureComponent.country_code = '1'; + fixtureComponent.local_phone_number = '123'; + fixture.detectChanges(); + const button = fixture.debugElement.nativeElement.querySelector( + 'ion-button' + ); + button.click(); + expect(onSignUpSpy).toHaveBeenCalled(); + expect(signUpSpy).toHaveBeenCalled(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/username-field.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/username-field.component.core.spec.ts index dfaac3cdcce..65f41caf2e0 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/username-field.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/username-field.component.core.spec.ts @@ -7,40 +7,40 @@ import { authModule } from '../../../__mocks__/mock_module'; import { PhoneFieldComponentCore } from '../../../components/authenticator/phone-field-component/phone-field.component.core'; describe('UsernameFieldComponentCore: ', () => { - let component: UsernameFieldComponentCore; - let fixtureComponent: UsernameFieldComponentCore; - let service: AmplifyService; - let fixture; + let component: UsernameFieldComponentCore; + let fixtureComponent: UsernameFieldComponentCore; + let service: AmplifyService; + let fixture; - beforeEach(() => { - service = new AmplifyService(authModule); - component = new UsernameFieldComponentCore(service); - TestBed.configureTestingModule({ - declarations: [ - UsernameFieldComponentCore, - MockComponent(PhoneFieldComponentCore) - ], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ] - }).compileComponents(); - fixture = TestBed.createComponent(UsernameFieldComponentCore); - fixtureComponent = fixture.componentInstance; - }); + beforeEach(() => { + service = new AmplifyService(authModule); + component = new UsernameFieldComponentCore(service); + TestBed.configureTestingModule({ + declarations: [ + UsernameFieldComponentCore, + MockComponent(PhoneFieldComponentCore), + ], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(UsernameFieldComponentCore); + fixtureComponent = fixture.componentInstance; + }); - afterEach(() => { - service = null; - component = null; - }); + afterEach(() => { + service = null; + component = null; + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); -}); \ No newline at end of file + it('...should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/packages/aws-amplify-angular/src/__tests__/components/authenticator/username-field.component.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/authenticator/username-field.component.ionic.spec.ts index 4a49c222ff2..d89d4bf86e4 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/authenticator/username-field.component.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/authenticator/username-field.component.ionic.spec.ts @@ -7,41 +7,41 @@ import { authModule } from '../../../__mocks__/mock_module'; import { PhoneFieldComponentIonic } from '../../../components/authenticator/phone-field-component/phone-field.component.ionic'; describe('UsernameFieldComponentCore: ', () => { - let component: UsernameFieldComponentIonic; - let fixtureComponent: UsernameFieldComponentIonic; - let service: AmplifyService; - let fixture; + let component: UsernameFieldComponentIonic; + let fixtureComponent: UsernameFieldComponentIonic; + let service: AmplifyService; + let fixture; - beforeEach(() => { - service = new AmplifyService(authModule); - component = new UsernameFieldComponentIonic(service); - TestBed.configureTestingModule({ - declarations: [ - UsernameFieldComponentIonic, - MockComponent(PhoneFieldComponentIonic) - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - providers: [ - { - provide: AmplifyService, - useFactory: () => { - return AmplifyModules({ - ...authModule - }); - } - } - ] - }).compileComponents(); - fixture = TestBed.createComponent(UsernameFieldComponentIonic); - fixtureComponent = fixture.componentInstance; - }); + beforeEach(() => { + service = new AmplifyService(authModule); + component = new UsernameFieldComponentIonic(service); + TestBed.configureTestingModule({ + declarations: [ + UsernameFieldComponentIonic, + MockComponent(PhoneFieldComponentIonic), + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [ + { + provide: AmplifyService, + useFactory: () => { + return AmplifyModules({ + ...authModule, + }); + }, + }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(UsernameFieldComponentIonic); + fixtureComponent = fixture.componentInstance; + }); - afterEach(() => { - service = null; - component = null; - }); + afterEach(() => { + service = null; + component = null; + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); -}); \ No newline at end of file + it('...should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/packages/aws-amplify-angular/src/__tests__/components/common/form.component.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/common/form.component.spec.ts index c4c715a7cd1..b8347d98a2a 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/common/form.component.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/common/form.component.spec.ts @@ -2,31 +2,32 @@ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { DebugElement } from '@angular/core'; import { By } from '@angular/platform-browser'; -import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, +} from '@angular/platform-browser-dynamic/testing'; import { FormComponent } from '../../../components/common/form.component'; - describe('FormComponent:', () => { +describe('FormComponent:', () => { + let component: FormComponent; - let component: FormComponent; - - beforeEach(() => { - component = new FormComponent(); - }); - - afterEach(() => { - component = null; - }); + beforeEach(() => { + component = new FormComponent(); + }); - it('...should be created', () => { - expect(component).toBeTruthy(); - }); + afterEach(() => { + component = null; + }); - it('...should have not have a default title', () => { - expect(component.title).toBeUndefined(); - }) + it('...should be created', () => { + expect(component).toBeTruthy(); + }); - afterAll(() => { - TestBed.resetTestEnvironment(); - }) + it('...should have not have a default title', () => { + expect(component.title).toBeUndefined(); + }); - }); + afterAll(() => { + TestBed.resetTestEnvironment(); + }); +}); diff --git a/packages/aws-amplify-angular/src/__tests__/components/interactions/chatbot.component.core.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/interactions/chatbot.component.core.ionic.spec.ts index b8a0e06047e..21fc074d207 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/interactions/chatbot.component.core.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/interactions/chatbot.component.core.ionic.spec.ts @@ -1,48 +1,41 @@ import { Component, ChangeDetectorRef } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService } from '../../../providers/amplify.service'; -import { ChatbotComponentIonic } -from '../../../components/interactions/chatbot/chatbot.component.ionic'; +import { ChatbotComponentIonic } from '../../../components/interactions/chatbot/chatbot.component.ionic'; import Amplify from 'aws-amplify'; - - describe('ChatbotComponentIonic: ', () => { - - let component: ChatbotComponentIonic; - let service: AmplifyService; - let ref: ChangeDetectorRef; - - - beforeEach(() => { - service = new AmplifyService(Amplify); - component = new ChatbotComponentIonic(ref, service); - }); - - afterEach(() => { - service = null; - component = null; - }); - - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have a performOnComplete method', () => { - expect(component.performOnComplete).toBeTruthy(); - }); - - it('...should have an onInputChange method', () => { - expect(component.onInputChange).toBeTruthy(); - }); - - it('...should have an onSubmit method', () => { - expect(component.onSubmit).toBeTruthy(); - }); - + let component: ChatbotComponentIonic; + let service: AmplifyService; + let ref: ChangeDetectorRef; + + beforeEach(() => { + service = new AmplifyService(Amplify); + component = new ChatbotComponentIonic(ref, service); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have a performOnComplete method', () => { + expect(component.performOnComplete).toBeTruthy(); + }); + + it('...should have an onInputChange method', () => { + expect(component.onInputChange).toBeTruthy(); + }); + + it('...should have an onSubmit method', () => { + expect(component.onSubmit).toBeTruthy(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/interactions/chatbot.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/interactions/chatbot.component.core.spec.ts index 6efacf739c6..d7964948ddb 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/interactions/chatbot.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/interactions/chatbot.component.core.spec.ts @@ -1,48 +1,41 @@ import { Component, ChangeDetectorRef } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService } from '../../../providers/amplify.service'; -import { ChatbotComponentCore } -from '../../../components/interactions/chatbot/chatbot.component.core'; +import { ChatbotComponentCore } from '../../../components/interactions/chatbot/chatbot.component.core'; import Amplify from 'aws-amplify'; - - describe('ChatbotComponentIonic: ', () => { - - let component: ChatbotComponentCore; - let service: AmplifyService; - let ref: ChangeDetectorRef; - - - beforeEach(() => { - service = new AmplifyService(Amplify); - component = new ChatbotComponentCore(ref, service); - }); - - afterEach(() => { - service = null; - component = null; - }); - - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have a performOnComplete method', () => { - expect(component.performOnComplete).toBeTruthy(); - }); - - it('...should have an onInputChange method', () => { - expect(component.onInputChange).toBeTruthy(); - }); - - it('...should have an onSubmit method', () => { - expect(component.onSubmit).toBeTruthy(); - }); - + let component: ChatbotComponentCore; + let service: AmplifyService; + let ref: ChangeDetectorRef; + + beforeEach(() => { + service = new AmplifyService(Amplify); + component = new ChatbotComponentCore(ref, service); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have a performOnComplete method', () => { + expect(component.performOnComplete).toBeTruthy(); + }); + + it('...should have an onInputChange method', () => { + expect(component.onInputChange).toBeTruthy(); + }); + + it('...should have an onSubmit method', () => { + expect(component.onSubmit).toBeTruthy(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/storage/s3-album.component.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/storage/s3-album.component.spec.ts index afb6b2adc66..ea7eef89731 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/storage/s3-album.component.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/storage/s3-album.component.spec.ts @@ -1,44 +1,38 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService } from '../../../providers/amplify.service'; import Amplify from 'aws-amplify'; -import { S3AlbumComponentCore } from - '../../../components/storage/s3-album-component/s3-album.component.core'; - +import { S3AlbumComponentCore } from '../../../components/storage/s3-album-component/s3-album.component.core'; describe('S3AlbumComponentCore: ', () => { - - let component: S3AlbumComponentCore; - let service: AmplifyService; - - beforeEach(() => { - service = new AmplifyService(Amplify); - component = new S3AlbumComponentCore(service); - }); - - afterEach(() => { - service = null; - component = null; - }); - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); + let component: S3AlbumComponentCore; + let service: AmplifyService; + + beforeEach(() => { + service = new AmplifyService(Amplify); + component = new S3AlbumComponentCore(service); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); }); - describe('S3AlbumComponentIonic: ', () => { + let component: S3AlbumComponentIonic; + let service: AmplifyService; - let component: S3AlbumComponentIonic; - let service: AmplifyService; - - beforeEach(() => { - service = new AmplifyService(); - component = new S3AlbumComponentCore(service); - }); - + beforeEach(() => { + service = new AmplifyService(); + component = new S3AlbumComponentCore(service); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/storage/s3-image.component.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/storage/s3-image.component.spec.ts index 986962f3a6f..aa34b487738 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/storage/s3-image.component.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/storage/s3-image.component.spec.ts @@ -1,33 +1,28 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; import { AmplifyService } from '../../../providers/amplify.service'; import Amplify from 'aws-amplify'; -import { S3ImageComponentCore } from -'../../../components/storage/s3-image-component/s3-image.component.core'; - +import { S3ImageComponentCore } from '../../../components/storage/s3-image-component/s3-image.component.core'; describe('S3ImageComponentCore: ', () => { - - let component: S3ImageComponentCore; - let service: AmplifyService; - - beforeEach(() => { - service = new AmplifyService(Amplify); - component = new S3ImageComponentCore(service); - }); - - afterEach(() => { - service = null; - component = null; - }); - - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - + let component: S3ImageComponentCore; + let service: AmplifyService; + + beforeEach(() => { + service = new AmplifyService(Amplify); + component = new S3ImageComponentCore(service); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/components/xr/sumerian-scene.component.core.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/xr/sumerian-scene.component.core.spec.ts index 4144ba719be..96b2f2f7b6d 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/xr/sumerian-scene.component.core.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/xr/sumerian-scene.component.core.spec.ts @@ -1,49 +1,46 @@ -import { AmplifyService } from '../../../providers/amplify.service' +import { AmplifyService } from '../../../providers/amplify.service'; import { SumerianSceneComponentCore } from '../../../components/xr/sumerian-scene-component/sumerian-scene.component.core'; import Amplify from 'aws-amplify'; describe('SumerianSceneComponentCore: ', () => { - - let component: SumerianSceneComponentCore; - let service: AmplifyService; - - - beforeEach(() => { - service = new AmplifyService(Amplify); - component = new SumerianSceneComponentCore(service); - }); - - afterEach(() => { - service = null; - component = null; - }); - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have a enterVR method', () => { - expect(component.toggleVRPresentation).toBeTruthy(); - }); - - it('...should have an loadAndStartScene method', () => { - expect(component.loadAndStartScene).toBeTruthy(); - }); - - it('...should have an maximize method', () => { - expect(component.maximize).toBeTruthy(); - }); - - it('...should have an minimize method', () => { - expect(component.minimize).toBeTruthy(); - }); - - it('...should have an setMuted method', () => { - expect(component.setMuted).toBeTruthy(); - }); - - it('...should have an onFullscreenChange method', () => { - expect(component.onFullscreenChange).toBeTruthy(); - }); - -}); \ No newline at end of file + let component: SumerianSceneComponentCore; + let service: AmplifyService; + + beforeEach(() => { + service = new AmplifyService(Amplify); + component = new SumerianSceneComponentCore(service); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have a enterVR method', () => { + expect(component.toggleVRPresentation).toBeTruthy(); + }); + + it('...should have an loadAndStartScene method', () => { + expect(component.loadAndStartScene).toBeTruthy(); + }); + + it('...should have an maximize method', () => { + expect(component.maximize).toBeTruthy(); + }); + + it('...should have an minimize method', () => { + expect(component.minimize).toBeTruthy(); + }); + + it('...should have an setMuted method', () => { + expect(component.setMuted).toBeTruthy(); + }); + + it('...should have an onFullscreenChange method', () => { + expect(component.onFullscreenChange).toBeTruthy(); + }); +}); diff --git a/packages/aws-amplify-angular/src/__tests__/components/xr/sumerian-scene.component.ionic.spec.ts b/packages/aws-amplify-angular/src/__tests__/components/xr/sumerian-scene.component.ionic.spec.ts index 83147544202..0e28c9b16e6 100644 --- a/packages/aws-amplify-angular/src/__tests__/components/xr/sumerian-scene.component.ionic.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/components/xr/sumerian-scene.component.ionic.spec.ts @@ -1,49 +1,46 @@ -import { AmplifyService } from '../../../providers/amplify.service' +import { AmplifyService } from '../../../providers/amplify.service'; import { SumerianSceneComponentIonic } from '../../../components/xr/sumerian-scene-component/sumerian-scene.component.ionic'; -import Amplify from 'aws-amplify'; +import Amplify from 'aws-amplify'; describe('SumerianSceneComponentIonic: ', () => { - - let component: SumerianSceneComponentIonic; - let service: AmplifyService; - - - beforeEach(() => { - service = new AmplifyService(Amplify); - component = new SumerianSceneComponentIonic(service); - }); - - afterEach(() => { - service = null; - component = null; - }); - - it('...should be created', () => { - expect(component).toBeTruthy(); - }); - - it('...should have a enterVR method', () => { - expect(component.toggleVRPresentation).toBeTruthy(); - }); - - it('...should have an loadAndStartScene method', () => { - expect(component.loadAndStartScene).toBeTruthy(); - }); - - it('...should have an maximize method', () => { - expect(component.maximize).toBeTruthy(); - }); - - it('...should have an minimize method', () => { - expect(component.minimize).toBeTruthy(); - }); - - it('...should have an setMuted method', () => { - expect(component.setMuted).toBeTruthy(); - }); - - it('...should have an onFullscreenChange method', () => { - expect(component.onFullscreenChange).toBeTruthy(); - }); - -}); \ No newline at end of file + let component: SumerianSceneComponentIonic; + let service: AmplifyService; + + beforeEach(() => { + service = new AmplifyService(Amplify); + component = new SumerianSceneComponentIonic(service); + }); + + afterEach(() => { + service = null; + component = null; + }); + + it('...should be created', () => { + expect(component).toBeTruthy(); + }); + + it('...should have a enterVR method', () => { + expect(component.toggleVRPresentation).toBeTruthy(); + }); + + it('...should have an loadAndStartScene method', () => { + expect(component.loadAndStartScene).toBeTruthy(); + }); + + it('...should have an maximize method', () => { + expect(component.maximize).toBeTruthy(); + }); + + it('...should have an minimize method', () => { + expect(component.minimize).toBeTruthy(); + }); + + it('...should have an setMuted method', () => { + expect(component.setMuted).toBeTruthy(); + }); + + it('...should have an onFullscreenChange method', () => { + expect(component.onFullscreenChange).toBeTruthy(); + }); +}); diff --git a/packages/aws-amplify-angular/src/__tests__/providers/auth.decorator.spec.ts b/packages/aws-amplify-angular/src/__tests__/providers/auth.decorator.spec.ts index b7bb0a70dfd..a291408a7fa 100644 --- a/packages/aws-amplify-angular/src/__tests__/providers/auth.decorator.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/providers/auth.decorator.spec.ts @@ -1,20 +1,22 @@ import { TestBed } from '@angular/core/testing'; -import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; -import { authDecorator } from '../../providers/auth.decorator'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, +} from '@angular/platform-browser-dynamic/testing'; +import { authDecorator } from '../../providers/auth.decorator'; describe('AuthDecorator', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [authDecorator], + }); + }); - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [authDecorator] - }); - }); + it('should be created', () => { + expect(authDecorator).toBeTruthy(); + }); - it('should be created', () => { - expect(authDecorator).toBeTruthy(); - }); - - afterAll(() => { - TestBed.resetTestEnvironment(); - }); + afterAll(() => { + TestBed.resetTestEnvironment(); + }); }); diff --git a/packages/aws-amplify-angular/src/__tests__/providers/auth.state.spec.ts b/packages/aws-amplify-angular/src/__tests__/providers/auth.state.spec.ts index e9deb169613..5f423b67467 100644 --- a/packages/aws-amplify-angular/src/__tests__/providers/auth.state.spec.ts +++ b/packages/aws-amplify-angular/src/__tests__/providers/auth.state.spec.ts @@ -1,20 +1,22 @@ import { TestBed, inject } from '@angular/core/testing'; -import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; -import {Subject} from 'rxjs'; -import { AuthState } from '../../providers/auth.state'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, +} from '@angular/platform-browser-dynamic/testing'; +import { Subject } from 'rxjs'; +import { AuthState } from '../../providers/auth.state'; describe('AuthState', () => { + beforeEach(() => { + TestBed.configureTestingModule({}); + }); - beforeEach(() => { - TestBed.configureTestingModule({}); - }); + it('...should be created', () => { + const AuthStateInterface = new Subject(); + expect(AuthStateInterface).toBeTruthy(); + }); - it('...should be created', () => { - const AuthStateInterface = new Subject(); - expect(AuthStateInterface).toBeTruthy(); - }); - - afterAll(() => { - TestBed.resetTestEnvironment(); - }); + afterAll(() => { + TestBed.resetTestEnvironment(); + }); }); diff --git a/packages/aws-amplify-angular/src/assets/countries.ts b/packages/aws-amplify-angular/src/assets/countries.ts index 4250992b8b6..45675c44e73 100644 --- a/packages/aws-amplify-angular/src/assets/countries.ts +++ b/packages/aws-amplify-angular/src/assets/countries.ts @@ -12,229 +12,229 @@ * and limitations under the License. */ // tslint:enable -class country{ - countryCode: string; - value: string; - label: string; +class country { + countryCode: string; + value: string; + label: string; } const countrylist = [ - { countryCode: 'US', value: '1', label: 'USA (+1)' }, - { countryCode: 'GB', value: '44', label: 'UK (+44)' }, - { countryCode: 'DZ', value: '213', label: 'Algeria (+213)' }, - { countryCode: 'AD', value: '376', label: 'Andorra (+376)' }, - { countryCode: 'AO', value: '244', label: 'Angola (+244)' }, - { countryCode: 'AI', value: '1264', label: 'Anguilla (+1264)' }, - { countryCode: 'AG', value: '1268', label: 'Antigua & Barbuda (+1268)' }, - { countryCode: 'AR', value: '54', label: 'Argentina (+54)' }, - { countryCode: 'AM', value: '374', label: 'Armenia (+374)' }, - { countryCode: 'AW', value: '297', label: 'Aruba (+297)' }, - { countryCode: 'AU', value: '61', label: 'Australia (+61)' }, - { countryCode: 'AT', value: '43', label: 'Austria (+43)' }, - { countryCode: 'AZ', value: '994', label: 'Azerbaijan (+994)' }, - { countryCode: 'BS', value: '1242', label: 'Bahamas (+1242)' }, - { countryCode: 'BH', value: '973', label: 'Bahrain (+973)' }, - { countryCode: 'BD', value: '880', label: 'Bangladesh (+880)' }, - { countryCode: 'BB', value: '1246', label: 'Barbados (+1246)' }, - { countryCode: 'BY', value: '375', label: 'Belarus (+375)' }, - { countryCode: 'BE', value: '32', label: 'Belgium (+32)' }, - { countryCode: 'BZ', value: '501', label: 'Belize (+501)' }, - { countryCode: 'BJ', value: '229', label: 'Benin (+229)' }, - { countryCode: 'BM', value: '1441', label: 'Bermuda (+1441)' }, - { countryCode: 'BT', value: '975', label: 'Bhutan (+975)' }, - { countryCode: 'BO', value: '591', label: 'Bolivia (+591)' }, - { countryCode: 'BA', value: '387', label: 'Bosnia Herzegovina (+387)' }, - { countryCode: 'BW', value: '267', label: 'Botswana (+267)' }, - { countryCode: 'BR', value: '55', label: 'Brazil (+55)' }, - { countryCode: 'BN', value: '673', label: 'Brunei (+673)' }, - { countryCode: 'BG', value: '359', label: 'Bulgaria (+359)' }, - { countryCode: 'BF', value: '226', label: 'Burkina Faso (+226)' }, - { countryCode: 'BI', value: '257', label: 'Burundi (+257)' }, - { countryCode: 'KH', value: '855', label: 'Cambodia (+855)' }, - { countryCode: 'CM', value: '237', label: 'Cameroon (+237)' }, - { countryCode: 'CA', value: '1', label: 'Canada (+1)' }, - { countryCode: 'CV', value: '238', label: 'Cape Verde Islands (+238)' }, - { countryCode: 'KY', value: '1345', label: 'Cayman Islands (+1345)' }, - { countryCode: 'CF', value: '236', label: 'Central African Republic (+236)' }, - { countryCode: 'CL', value: '56', label: 'Chile (+56)' }, - { countryCode: 'CN', value: '86', label: 'China (+86)' }, - { countryCode: 'CO', value: '57', label: 'Colombia (+57)' }, - { countryCode: 'KM', value: '269', label: 'Comoros (+269)' }, - { countryCode: 'CG', value: '242', label: 'Congo (+242)' }, - { countryCode: 'CK', value: '682', label: 'Cook Islands (+682)' }, - { countryCode: 'CR', value: '506', label: 'Costa Rica (+506)' }, - { countryCode: 'HR', value: '385', label: 'Croatia (+385)' }, - { countryCode: 'CU', value: '53', label: 'Cuba (+53)' }, - { countryCode: 'CW', value: '599', label: 'Curacao (+599)' }, - { countryCode: 'CY', value: '90392', label: 'Cyprus North (+90392)' }, - { countryCode: 'CY', value: '357', label: 'Cyprus South (+357)' }, - { countryCode: 'CZ', value: '42', label: 'Czech Republic (+42)' }, - { countryCode: 'DK', value: '45', label: 'Denmark (+45)' }, - { countryCode: 'DJ', value: '253', label: 'Djibouti (+253)' }, - { countryCode: 'DM', value: '1809', label: 'Dominica (+1809)' }, - { countryCode: 'DO', value: '1809', label: 'Dominican Republic (+1809)' }, - { countryCode: 'EC', value: '593', label: 'Ecuador (+593)' }, - { countryCode: 'EG', value: '20', label: 'Egypt (+20)' }, - { countryCode: 'SV', value: '503', label: 'El Salvador (+503)' }, - { countryCode: 'GQ', value: '240', label: 'Equatorial Guinea (+240)' }, - { countryCode: 'ER', value: '291', label: 'Eritrea (+291)' }, - { countryCode: 'EE', value: '372', label: 'Estonia (+372)' }, - { countryCode: 'ET', value: '251', label: 'Ethiopia (+251)' }, - { countryCode: 'FK', value: '500', label: 'Falkland Islands (+500)' }, - { countryCode: 'FO', value: '298', label: 'Faroe Islands (+298)' }, - { countryCode: 'FJ', value: '679', label: 'Fiji (+679)' }, - { countryCode: 'FI', value: '358', label: 'Finland (+358)' }, - { countryCode: 'FR', value: '33', label: 'France (+33)' }, - { countryCode: 'GF', value: '594', label: 'French Guiana (+594)' }, - { countryCode: 'PF', value: '689', label: 'French Polynesia (+689)' }, - { countryCode: 'GA', value: '241', label: 'Gabon (+241)' }, - { countryCode: 'GM', value: '220', label: 'Gambia (+220)' }, - { countryCode: 'GE', value: '7880', label: 'Georgia (+7880)' }, - { countryCode: 'DE', value: '49', label: 'Germany (+49)' }, - { countryCode: 'GH', value: '233', label: 'Ghana (+233)' }, - { countryCode: 'GI', value: '350', label: 'Gibraltar (+350)' }, - { countryCode: 'GR', value: '30', label: 'Greece (+30)' }, - { countryCode: 'GL', value: '299', label: 'Greenland (+299)' }, - { countryCode: 'GD', value: '1473', label: 'Grenada (+1473)' }, - { countryCode: 'GP', value: '590', label: 'Guadeloupe (+590)' }, - { countryCode: 'GU', value: '671', label: 'Guam (+671)' }, - { countryCode: 'GT', value: '502', label: 'Guatemala (+502)' }, - { countryCode: 'GN', value: '224', label: 'Guinea (+224)' }, - { countryCode: 'GW', value: '245', label: 'Guinea - Bissau (+245)' }, - { countryCode: 'GY', value: '592', label: 'Guyana (+592)' }, - { countryCode: 'HT', value: '509', label: 'Haiti (+509)' }, - { countryCode: 'HN', value: '504', label: 'Honduras (+504)' }, - { countryCode: 'HK', value: '852', label: 'Hong Kong (+852)' }, - { countryCode: 'HU', value: '36', label: 'Hungary (+36)' }, - { countryCode: 'IS', value: '354', label: 'Iceland (+354)' }, - { countryCode: 'IN', value: '91', label: 'India (+91)' }, - { countryCode: 'ID', value: '62', label: 'Indonesia (+62)' }, - { countryCode: 'IR', value: '98', label: 'Iran (+98)' }, - { countryCode: 'IQ', value: '964', label: 'Iraq (+964)' }, - { countryCode: 'IE', value: '353', label: 'Ireland (+353)' }, - { countryCode: 'IL', value: '972', label: 'Israel (+972)' }, - { countryCode: 'IT', value: '39', label: 'Italy (+39)' }, - { countryCode: 'JM', value: '1876', label: 'Jamaica (+1876)' }, - { countryCode: 'JP', value: '81', label: 'Japan (+81)' }, - { countryCode: 'JO', value: '962', label: 'Jordan (+962)' }, - { countryCode: 'KZ', value: '7', label: 'Kazakhstan (+7)' }, - { countryCode: 'KE', value: '254', label: 'Kenya (+254)' }, - { countryCode: 'KI', value: '686', label: 'Kiribati (+686)' }, - { countryCode: 'KP', value: '850', label: 'Korea North (+850)' }, - { countryCode: 'KR', value: '82', label: 'Korea South (+82)' }, - { countryCode: 'KW', value: '965', label: 'Kuwait (+965)' }, - { countryCode: 'KG', value: '996', label: 'Kyrgyzstan (+996)' }, - { countryCode: 'LA', value: '856', label: 'Laos (+856)' }, - { countryCode: 'LV', value: '371', label: 'Latvia (+371)' }, - { countryCode: 'LB', value: '961', label: 'Lebanon (+961)' }, - { countryCode: 'LS', value: '266', label: 'Lesotho (+266)' }, - { countryCode: 'LR', value: '231', label: 'Liberia (+231)' }, - { countryCode: 'LY', value: '218', label: 'Libya (+218)' }, - { countryCode: 'LI', value: '417', label: 'Liechtenstein (+417)' }, - { countryCode: 'LT', value: '370', label: 'Lithuania (+370)' }, - { countryCode: 'LU', value: '352', label: 'Luxembourg (+352)' }, - { countryCode: 'MO', value: '853', label: 'Macao (+853)' }, - { countryCode: 'MK', value: '389', label: 'Macedonia (+389)' }, - { countryCode: 'MG', value: '261', label: 'Madagascar (+261)' }, - { countryCode: 'MW', value: '265', label: 'Malawi (+265)' }, - { countryCode: 'MY', value: '60', label: 'Malaysia (+60)' }, - { countryCode: 'MV', value: '960', label: 'Maldives (+960)' }, - { countryCode: 'ML', value: '223', label: 'Mali (+223)' }, - { countryCode: 'MT', value: '356', label: 'Malta (+356)' }, - { countryCode: 'MH', value: '692', label: 'Marshall Islands (+692)' }, - { countryCode: 'MQ', value: '596', label: 'Martinique (+596)' }, - { countryCode: 'MR', value: '222', label: 'Mauritania (+222)' }, - { countryCode: 'YT', value: '269', label: 'Mayotte (+269)' }, - { countryCode: 'MX', value: '52', label: 'Mexico (+52)' }, - { countryCode: 'FM', value: '691', label: 'Micronesia (+691)' }, - { countryCode: 'MD', value: '373', label: 'Moldova (+373)' }, - { countryCode: 'MC', value: '377', label: 'Monaco (+377)' }, - { countryCode: 'MN', value: '976', label: 'Mongolia (+976)' }, - { countryCode: 'MS', value: '1664', label: 'Montserrat (+1664)' }, - { countryCode: 'MA', value: '212', label: 'Morocco (+212)' }, - { countryCode: 'MZ', value: '258', label: 'Mozambique (+258)' }, - { countryCode: 'MN', value: '95', label: 'Myanmar (+95)' }, - { countryCode: 'NA', value: '264', label: 'Namibia (+264)' }, - { countryCode: 'NR', value: '674', label: 'Nauru (+674)' }, - { countryCode: 'NP', value: '977', label: 'Nepal (+977)' }, - { countryCode: 'NL', value: '31', label: 'Netherlands (+31)' }, - { countryCode: 'NC', value: '687', label: 'New Caledonia (+687)' }, - { countryCode: 'NZ', value: '64', label: 'New Zealand (+64)' }, - { countryCode: 'NI', value: '505', label: 'Nicaragua (+505)' }, - { countryCode: 'NE', value: '227', label: 'Niger (+227)' }, - { countryCode: 'NG', value: '234', label: 'Nigeria (+234)' }, - { countryCode: 'NU', value: '683', label: 'Niue (+683)' }, - { countryCode: 'NF', value: '672', label: 'Norfolk Islands (+672)' }, - { countryCode: 'NP', value: '670', label: 'Northern Marianas (+670)' }, - { countryCode: 'NO', value: '47', label: 'Norway (+47)' }, - { countryCode: 'OM', value: '968', label: 'Oman (+968)' }, - { countryCode: 'PW', value: '680', label: 'Palau (+680)' }, - { countryCode: 'PA', value: '507', label: 'Panama (+507)' }, - { countryCode: 'PG', value: '675', label: 'Papua New Guinea (+675)' }, - { countryCode: 'PY', value: '595', label: 'Paraguay (+595)' }, - { countryCode: 'PE', value: '51', label: 'Peru (+51)' }, - { countryCode: 'PH', value: '63', label: 'Philippines (+63)' }, - { countryCode: 'PL', value: '48', label: 'Poland (+48)' }, - { countryCode: 'PT', value: '351', label: 'Portugal (+351)' }, - { countryCode: 'PR', value: '1787', label: 'Puerto Rico (+1787)' }, - { countryCode: 'QA', value: '974', label: 'Qatar (+974)' }, - { countryCode: 'RE', value: '262', label: 'Reunion (+262)' }, - { countryCode: 'RO', value: '40', label: 'Romania (+40)' }, - { countryCode: 'RU', value: '7', label: 'Russia (+7)' }, - { countryCode: 'RW', value: '250', label: 'Rwanda (+250)' }, - { countryCode: 'SM', value: '378', label: 'San Marino (+378)' }, - { countryCode: 'ST', value: '239', label: 'Sao Tome & Principe (+239)' }, - { countryCode: 'SA', value: '966', label: 'Saudi Arabia (+966)' }, - { countryCode: 'SN', value: '221', label: 'Senegal (+221)' }, - { countryCode: 'CS', value: '381', label: 'Serbia (+381)' }, - { countryCode: 'SC', value: '248', label: 'Seychelles (+248)' }, - { countryCode: 'SL', value: '232', label: 'Sierra Leone (+232)' }, - { countryCode: 'SX', value: '1', label: 'Sint Maarten (+1)' }, - { countryCode: 'SG', value: '65', label: 'Singapore (+65)' }, - { countryCode: 'SK', value: '421', label: 'Slovak Republic (+421)' }, - { countryCode: 'SI', value: '386', label: 'Slovenia (+386)' }, - { countryCode: 'SB', value: '677', label: 'Solomon Islands (+677)' }, - { countryCode: 'SO', value: '252', label: 'Somalia (+252)' }, - { countryCode: 'ZA', value: '27', label: 'South Africa (+27)' }, - { countryCode: 'ES', value: '34', label: 'Spain (+34)' }, - { countryCode: 'LK', value: '94', label: 'Sri Lanka (+94)' }, - { countryCode: 'SH', value: '290', label: 'St. Helena (+290)' }, - { countryCode: 'KN', value: '1869', label: 'St. Kitts (+1869)' }, - { countryCode: 'SC', value: '1758', label: 'St. Lucia (+1758)' }, - { countryCode: 'SD', value: '249', label: 'Sudan (+249)' }, - { countryCode: 'SR', value: '597', label: 'Suriname (+597)' }, - { countryCode: 'SZ', value: '268', label: 'Swaziland (+268)' }, - { countryCode: 'SE', value: '46', label: 'Sweden (+46)' }, - { countryCode: 'CH', value: '41', label: 'Switzerland (+41)' }, - { countryCode: 'SI', value: '963', label: 'Syria (+963)' }, - { countryCode: 'TW', value: '886', label: 'Taiwan (+886)' }, - { countryCode: 'TJ', value: '7', label: 'Tajikstan (+7)' }, - { countryCode: 'TH', value: '66', label: 'Thailand (+66)' }, - { countryCode: 'TG', value: '228', label: 'Togo (+228)' }, - { countryCode: 'TO', value: '676', label: 'Tonga (+676)' }, - { countryCode: 'TT', value: '1868', label: 'Trinidad & Tobago (+1868)' }, - { countryCode: 'TN', value: '216', label: 'Tunisia (+216)' }, - { countryCode: 'TR', value: '90', label: 'Turkey (+90)' }, - { countryCode: 'TM', value: '7', label: 'Turkmenistan (+7)' }, - { countryCode: 'TM', value: '993', label: 'Turkmenistan (+993)' }, - { countryCode: 'TC', value: '1649', label: 'Turks & Caicos Islands (+1649)' }, - { countryCode: 'TV', value: '688', label: 'Tuvalu (+688)' }, - { countryCode: 'UG', value: '256', label: 'Uganda (+256)' }, - { countryCode: 'UA', value: '380', label: 'Ukraine (+380)' }, - { countryCode: 'AE', value: '971', label: 'United Arab Emirates (+971)' }, - { countryCode: 'UY', value: '598', label: 'Uruguay (+598)' }, - { countryCode: 'UZ', value: '7', label: 'Uzbekistan (+7)' }, - { countryCode: 'VU', value: '678', label: 'Vanuatu (+678)' }, - { countryCode: 'VA', value: '379', label: 'Vatican City (+379)' }, - { countryCode: 'VE', value: '58', label: 'Venezuela (+58)' }, - { countryCode: 'VN', value: '84', label: 'Vietnam (+84)' }, - { countryCode: 'VG', value: '84', label: 'Virgin Islands - British (+1284)' }, - { countryCode: 'VI', value: '84', label: 'Virgin Islands - US (+1340)' }, - { countryCode: 'WF', value: '681', label: 'Wallis and Futuna (+681)' }, - { countryCode: 'YE', value: '969', label: 'Yemen (North) (+969)' }, - { countryCode: 'YE', value: '967', label: 'Yemen (South) (+967)' }, - { countryCode: 'ZM', value: '260', label: 'Zambia (+260)' }, - { countryCode: 'ZW', value: '263', label: 'Zimbabwe (+263)' }, + { countryCode: 'US', value: '1', label: 'USA (+1)' }, + { countryCode: 'GB', value: '44', label: 'UK (+44)' }, + { countryCode: 'DZ', value: '213', label: 'Algeria (+213)' }, + { countryCode: 'AD', value: '376', label: 'Andorra (+376)' }, + { countryCode: 'AO', value: '244', label: 'Angola (+244)' }, + { countryCode: 'AI', value: '1264', label: 'Anguilla (+1264)' }, + { countryCode: 'AG', value: '1268', label: 'Antigua & Barbuda (+1268)' }, + { countryCode: 'AR', value: '54', label: 'Argentina (+54)' }, + { countryCode: 'AM', value: '374', label: 'Armenia (+374)' }, + { countryCode: 'AW', value: '297', label: 'Aruba (+297)' }, + { countryCode: 'AU', value: '61', label: 'Australia (+61)' }, + { countryCode: 'AT', value: '43', label: 'Austria (+43)' }, + { countryCode: 'AZ', value: '994', label: 'Azerbaijan (+994)' }, + { countryCode: 'BS', value: '1242', label: 'Bahamas (+1242)' }, + { countryCode: 'BH', value: '973', label: 'Bahrain (+973)' }, + { countryCode: 'BD', value: '880', label: 'Bangladesh (+880)' }, + { countryCode: 'BB', value: '1246', label: 'Barbados (+1246)' }, + { countryCode: 'BY', value: '375', label: 'Belarus (+375)' }, + { countryCode: 'BE', value: '32', label: 'Belgium (+32)' }, + { countryCode: 'BZ', value: '501', label: 'Belize (+501)' }, + { countryCode: 'BJ', value: '229', label: 'Benin (+229)' }, + { countryCode: 'BM', value: '1441', label: 'Bermuda (+1441)' }, + { countryCode: 'BT', value: '975', label: 'Bhutan (+975)' }, + { countryCode: 'BO', value: '591', label: 'Bolivia (+591)' }, + { countryCode: 'BA', value: '387', label: 'Bosnia Herzegovina (+387)' }, + { countryCode: 'BW', value: '267', label: 'Botswana (+267)' }, + { countryCode: 'BR', value: '55', label: 'Brazil (+55)' }, + { countryCode: 'BN', value: '673', label: 'Brunei (+673)' }, + { countryCode: 'BG', value: '359', label: 'Bulgaria (+359)' }, + { countryCode: 'BF', value: '226', label: 'Burkina Faso (+226)' }, + { countryCode: 'BI', value: '257', label: 'Burundi (+257)' }, + { countryCode: 'KH', value: '855', label: 'Cambodia (+855)' }, + { countryCode: 'CM', value: '237', label: 'Cameroon (+237)' }, + { countryCode: 'CA', value: '1', label: 'Canada (+1)' }, + { countryCode: 'CV', value: '238', label: 'Cape Verde Islands (+238)' }, + { countryCode: 'KY', value: '1345', label: 'Cayman Islands (+1345)' }, + { countryCode: 'CF', value: '236', label: 'Central African Republic (+236)' }, + { countryCode: 'CL', value: '56', label: 'Chile (+56)' }, + { countryCode: 'CN', value: '86', label: 'China (+86)' }, + { countryCode: 'CO', value: '57', label: 'Colombia (+57)' }, + { countryCode: 'KM', value: '269', label: 'Comoros (+269)' }, + { countryCode: 'CG', value: '242', label: 'Congo (+242)' }, + { countryCode: 'CK', value: '682', label: 'Cook Islands (+682)' }, + { countryCode: 'CR', value: '506', label: 'Costa Rica (+506)' }, + { countryCode: 'HR', value: '385', label: 'Croatia (+385)' }, + { countryCode: 'CU', value: '53', label: 'Cuba (+53)' }, + { countryCode: 'CW', value: '599', label: 'Curacao (+599)' }, + { countryCode: 'CY', value: '90392', label: 'Cyprus North (+90392)' }, + { countryCode: 'CY', value: '357', label: 'Cyprus South (+357)' }, + { countryCode: 'CZ', value: '42', label: 'Czech Republic (+42)' }, + { countryCode: 'DK', value: '45', label: 'Denmark (+45)' }, + { countryCode: 'DJ', value: '253', label: 'Djibouti (+253)' }, + { countryCode: 'DM', value: '1809', label: 'Dominica (+1809)' }, + { countryCode: 'DO', value: '1809', label: 'Dominican Republic (+1809)' }, + { countryCode: 'EC', value: '593', label: 'Ecuador (+593)' }, + { countryCode: 'EG', value: '20', label: 'Egypt (+20)' }, + { countryCode: 'SV', value: '503', label: 'El Salvador (+503)' }, + { countryCode: 'GQ', value: '240', label: 'Equatorial Guinea (+240)' }, + { countryCode: 'ER', value: '291', label: 'Eritrea (+291)' }, + { countryCode: 'EE', value: '372', label: 'Estonia (+372)' }, + { countryCode: 'ET', value: '251', label: 'Ethiopia (+251)' }, + { countryCode: 'FK', value: '500', label: 'Falkland Islands (+500)' }, + { countryCode: 'FO', value: '298', label: 'Faroe Islands (+298)' }, + { countryCode: 'FJ', value: '679', label: 'Fiji (+679)' }, + { countryCode: 'FI', value: '358', label: 'Finland (+358)' }, + { countryCode: 'FR', value: '33', label: 'France (+33)' }, + { countryCode: 'GF', value: '594', label: 'French Guiana (+594)' }, + { countryCode: 'PF', value: '689', label: 'French Polynesia (+689)' }, + { countryCode: 'GA', value: '241', label: 'Gabon (+241)' }, + { countryCode: 'GM', value: '220', label: 'Gambia (+220)' }, + { countryCode: 'GE', value: '7880', label: 'Georgia (+7880)' }, + { countryCode: 'DE', value: '49', label: 'Germany (+49)' }, + { countryCode: 'GH', value: '233', label: 'Ghana (+233)' }, + { countryCode: 'GI', value: '350', label: 'Gibraltar (+350)' }, + { countryCode: 'GR', value: '30', label: 'Greece (+30)' }, + { countryCode: 'GL', value: '299', label: 'Greenland (+299)' }, + { countryCode: 'GD', value: '1473', label: 'Grenada (+1473)' }, + { countryCode: 'GP', value: '590', label: 'Guadeloupe (+590)' }, + { countryCode: 'GU', value: '671', label: 'Guam (+671)' }, + { countryCode: 'GT', value: '502', label: 'Guatemala (+502)' }, + { countryCode: 'GN', value: '224', label: 'Guinea (+224)' }, + { countryCode: 'GW', value: '245', label: 'Guinea - Bissau (+245)' }, + { countryCode: 'GY', value: '592', label: 'Guyana (+592)' }, + { countryCode: 'HT', value: '509', label: 'Haiti (+509)' }, + { countryCode: 'HN', value: '504', label: 'Honduras (+504)' }, + { countryCode: 'HK', value: '852', label: 'Hong Kong (+852)' }, + { countryCode: 'HU', value: '36', label: 'Hungary (+36)' }, + { countryCode: 'IS', value: '354', label: 'Iceland (+354)' }, + { countryCode: 'IN', value: '91', label: 'India (+91)' }, + { countryCode: 'ID', value: '62', label: 'Indonesia (+62)' }, + { countryCode: 'IR', value: '98', label: 'Iran (+98)' }, + { countryCode: 'IQ', value: '964', label: 'Iraq (+964)' }, + { countryCode: 'IE', value: '353', label: 'Ireland (+353)' }, + { countryCode: 'IL', value: '972', label: 'Israel (+972)' }, + { countryCode: 'IT', value: '39', label: 'Italy (+39)' }, + { countryCode: 'JM', value: '1876', label: 'Jamaica (+1876)' }, + { countryCode: 'JP', value: '81', label: 'Japan (+81)' }, + { countryCode: 'JO', value: '962', label: 'Jordan (+962)' }, + { countryCode: 'KZ', value: '7', label: 'Kazakhstan (+7)' }, + { countryCode: 'KE', value: '254', label: 'Kenya (+254)' }, + { countryCode: 'KI', value: '686', label: 'Kiribati (+686)' }, + { countryCode: 'KP', value: '850', label: 'Korea North (+850)' }, + { countryCode: 'KR', value: '82', label: 'Korea South (+82)' }, + { countryCode: 'KW', value: '965', label: 'Kuwait (+965)' }, + { countryCode: 'KG', value: '996', label: 'Kyrgyzstan (+996)' }, + { countryCode: 'LA', value: '856', label: 'Laos (+856)' }, + { countryCode: 'LV', value: '371', label: 'Latvia (+371)' }, + { countryCode: 'LB', value: '961', label: 'Lebanon (+961)' }, + { countryCode: 'LS', value: '266', label: 'Lesotho (+266)' }, + { countryCode: 'LR', value: '231', label: 'Liberia (+231)' }, + { countryCode: 'LY', value: '218', label: 'Libya (+218)' }, + { countryCode: 'LI', value: '417', label: 'Liechtenstein (+417)' }, + { countryCode: 'LT', value: '370', label: 'Lithuania (+370)' }, + { countryCode: 'LU', value: '352', label: 'Luxembourg (+352)' }, + { countryCode: 'MO', value: '853', label: 'Macao (+853)' }, + { countryCode: 'MK', value: '389', label: 'Macedonia (+389)' }, + { countryCode: 'MG', value: '261', label: 'Madagascar (+261)' }, + { countryCode: 'MW', value: '265', label: 'Malawi (+265)' }, + { countryCode: 'MY', value: '60', label: 'Malaysia (+60)' }, + { countryCode: 'MV', value: '960', label: 'Maldives (+960)' }, + { countryCode: 'ML', value: '223', label: 'Mali (+223)' }, + { countryCode: 'MT', value: '356', label: 'Malta (+356)' }, + { countryCode: 'MH', value: '692', label: 'Marshall Islands (+692)' }, + { countryCode: 'MQ', value: '596', label: 'Martinique (+596)' }, + { countryCode: 'MR', value: '222', label: 'Mauritania (+222)' }, + { countryCode: 'YT', value: '269', label: 'Mayotte (+269)' }, + { countryCode: 'MX', value: '52', label: 'Mexico (+52)' }, + { countryCode: 'FM', value: '691', label: 'Micronesia (+691)' }, + { countryCode: 'MD', value: '373', label: 'Moldova (+373)' }, + { countryCode: 'MC', value: '377', label: 'Monaco (+377)' }, + { countryCode: 'MN', value: '976', label: 'Mongolia (+976)' }, + { countryCode: 'MS', value: '1664', label: 'Montserrat (+1664)' }, + { countryCode: 'MA', value: '212', label: 'Morocco (+212)' }, + { countryCode: 'MZ', value: '258', label: 'Mozambique (+258)' }, + { countryCode: 'MN', value: '95', label: 'Myanmar (+95)' }, + { countryCode: 'NA', value: '264', label: 'Namibia (+264)' }, + { countryCode: 'NR', value: '674', label: 'Nauru (+674)' }, + { countryCode: 'NP', value: '977', label: 'Nepal (+977)' }, + { countryCode: 'NL', value: '31', label: 'Netherlands (+31)' }, + { countryCode: 'NC', value: '687', label: 'New Caledonia (+687)' }, + { countryCode: 'NZ', value: '64', label: 'New Zealand (+64)' }, + { countryCode: 'NI', value: '505', label: 'Nicaragua (+505)' }, + { countryCode: 'NE', value: '227', label: 'Niger (+227)' }, + { countryCode: 'NG', value: '234', label: 'Nigeria (+234)' }, + { countryCode: 'NU', value: '683', label: 'Niue (+683)' }, + { countryCode: 'NF', value: '672', label: 'Norfolk Islands (+672)' }, + { countryCode: 'NP', value: '670', label: 'Northern Marianas (+670)' }, + { countryCode: 'NO', value: '47', label: 'Norway (+47)' }, + { countryCode: 'OM', value: '968', label: 'Oman (+968)' }, + { countryCode: 'PW', value: '680', label: 'Palau (+680)' }, + { countryCode: 'PA', value: '507', label: 'Panama (+507)' }, + { countryCode: 'PG', value: '675', label: 'Papua New Guinea (+675)' }, + { countryCode: 'PY', value: '595', label: 'Paraguay (+595)' }, + { countryCode: 'PE', value: '51', label: 'Peru (+51)' }, + { countryCode: 'PH', value: '63', label: 'Philippines (+63)' }, + { countryCode: 'PL', value: '48', label: 'Poland (+48)' }, + { countryCode: 'PT', value: '351', label: 'Portugal (+351)' }, + { countryCode: 'PR', value: '1787', label: 'Puerto Rico (+1787)' }, + { countryCode: 'QA', value: '974', label: 'Qatar (+974)' }, + { countryCode: 'RE', value: '262', label: 'Reunion (+262)' }, + { countryCode: 'RO', value: '40', label: 'Romania (+40)' }, + { countryCode: 'RU', value: '7', label: 'Russia (+7)' }, + { countryCode: 'RW', value: '250', label: 'Rwanda (+250)' }, + { countryCode: 'SM', value: '378', label: 'San Marino (+378)' }, + { countryCode: 'ST', value: '239', label: 'Sao Tome & Principe (+239)' }, + { countryCode: 'SA', value: '966', label: 'Saudi Arabia (+966)' }, + { countryCode: 'SN', value: '221', label: 'Senegal (+221)' }, + { countryCode: 'CS', value: '381', label: 'Serbia (+381)' }, + { countryCode: 'SC', value: '248', label: 'Seychelles (+248)' }, + { countryCode: 'SL', value: '232', label: 'Sierra Leone (+232)' }, + { countryCode: 'SX', value: '1', label: 'Sint Maarten (+1)' }, + { countryCode: 'SG', value: '65', label: 'Singapore (+65)' }, + { countryCode: 'SK', value: '421', label: 'Slovak Republic (+421)' }, + { countryCode: 'SI', value: '386', label: 'Slovenia (+386)' }, + { countryCode: 'SB', value: '677', label: 'Solomon Islands (+677)' }, + { countryCode: 'SO', value: '252', label: 'Somalia (+252)' }, + { countryCode: 'ZA', value: '27', label: 'South Africa (+27)' }, + { countryCode: 'ES', value: '34', label: 'Spain (+34)' }, + { countryCode: 'LK', value: '94', label: 'Sri Lanka (+94)' }, + { countryCode: 'SH', value: '290', label: 'St. Helena (+290)' }, + { countryCode: 'KN', value: '1869', label: 'St. Kitts (+1869)' }, + { countryCode: 'SC', value: '1758', label: 'St. Lucia (+1758)' }, + { countryCode: 'SD', value: '249', label: 'Sudan (+249)' }, + { countryCode: 'SR', value: '597', label: 'Suriname (+597)' }, + { countryCode: 'SZ', value: '268', label: 'Swaziland (+268)' }, + { countryCode: 'SE', value: '46', label: 'Sweden (+46)' }, + { countryCode: 'CH', value: '41', label: 'Switzerland (+41)' }, + { countryCode: 'SI', value: '963', label: 'Syria (+963)' }, + { countryCode: 'TW', value: '886', label: 'Taiwan (+886)' }, + { countryCode: 'TJ', value: '7', label: 'Tajikstan (+7)' }, + { countryCode: 'TH', value: '66', label: 'Thailand (+66)' }, + { countryCode: 'TG', value: '228', label: 'Togo (+228)' }, + { countryCode: 'TO', value: '676', label: 'Tonga (+676)' }, + { countryCode: 'TT', value: '1868', label: 'Trinidad & Tobago (+1868)' }, + { countryCode: 'TN', value: '216', label: 'Tunisia (+216)' }, + { countryCode: 'TR', value: '90', label: 'Turkey (+90)' }, + { countryCode: 'TM', value: '7', label: 'Turkmenistan (+7)' }, + { countryCode: 'TM', value: '993', label: 'Turkmenistan (+993)' }, + { countryCode: 'TC', value: '1649', label: 'Turks & Caicos Islands (+1649)' }, + { countryCode: 'TV', value: '688', label: 'Tuvalu (+688)' }, + { countryCode: 'UG', value: '256', label: 'Uganda (+256)' }, + { countryCode: 'UA', value: '380', label: 'Ukraine (+380)' }, + { countryCode: 'AE', value: '971', label: 'United Arab Emirates (+971)' }, + { countryCode: 'UY', value: '598', label: 'Uruguay (+598)' }, + { countryCode: 'UZ', value: '7', label: 'Uzbekistan (+7)' }, + { countryCode: 'VU', value: '678', label: 'Vanuatu (+678)' }, + { countryCode: 'VA', value: '379', label: 'Vatican City (+379)' }, + { countryCode: 'VE', value: '58', label: 'Venezuela (+58)' }, + { countryCode: 'VN', value: '84', label: 'Vietnam (+84)' }, + { countryCode: 'VG', value: '84', label: 'Virgin Islands - British (+1284)' }, + { countryCode: 'VI', value: '84', label: 'Virgin Islands - US (+1340)' }, + { countryCode: 'WF', value: '681', label: 'Wallis and Futuna (+681)' }, + { countryCode: 'YE', value: '969', label: 'Yemen (North) (+969)' }, + { countryCode: 'YE', value: '967', label: 'Yemen (South) (+967)' }, + { countryCode: 'ZM', value: '260', label: 'Zambia (+260)' }, + { countryCode: 'ZW', value: '263', label: 'Zimbabwe (+263)' }, ]; -export { countrylist, country} ; +export { countrylist, country }; diff --git a/packages/aws-amplify-angular/src/assets/data-test-attributes.ts b/packages/aws-amplify-angular/src/assets/data-test-attributes.ts index 4708e9a889c..791b65f14f3 100644 --- a/packages/aws-amplify-angular/src/assets/data-test-attributes.ts +++ b/packages/aws-amplify-angular/src/assets/data-test-attributes.ts @@ -1,4 +1,3 @@ - // tslint:disable /* * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -15,164 +14,163 @@ // tslint:enable // Auth const signIn = { - section: 'sign-in-section', - headerSection: 'sign-in-header-section', - bodySection: 'sign-in-body-section', - footerSection: 'sign-in-footer-section', - usernameInput: 'username-input', - passwordInput: 'sign-in-password-input', - forgotPasswordLink: 'sign-in-forgot-password-link', - signInButton: 'sign-in-sign-in-button', - createAccountLink: 'sign-in-create-account-link', - signInError: 'authenticator-error', + section: 'sign-in-section', + headerSection: 'sign-in-header-section', + bodySection: 'sign-in-body-section', + footerSection: 'sign-in-footer-section', + usernameInput: 'username-input', + passwordInput: 'sign-in-password-input', + forgotPasswordLink: 'sign-in-forgot-password-link', + signInButton: 'sign-in-sign-in-button', + createAccountLink: 'sign-in-create-account-link', + signInError: 'authenticator-error', }; const signOut = { - button: 'sign-out-button', - section: 'sign-out-section', + button: 'sign-out-button', + section: 'sign-out-section', }; const signUp = { - section: 'sign-up-section', - headerSection: 'sign-up-header-section', - bodySection: 'sign-up-body-section', - nonPhoneNumberInput: 'sign-up-non-phone-number-input', - phoneNumberInput: 'sign-up-phone-number-input', - dialCodeSelect: 'sign-up-dial-code-select', - footerSection: 'sign-up-footer-section', - createAccountButton: 'sign-up-create-account-button', - signInLink: 'sign-up-sign-in-link', - signUpButton: 'sign-up-sign-up-button', - signInButton: 'sign-up-sign-in-button', - confirmButton: 'sign-up-confirm-button', + section: 'sign-up-section', + headerSection: 'sign-up-header-section', + bodySection: 'sign-up-body-section', + nonPhoneNumberInput: 'sign-up-non-phone-number-input', + phoneNumberInput: 'sign-up-phone-number-input', + dialCodeSelect: 'sign-up-dial-code-select', + footerSection: 'sign-up-footer-section', + createAccountButton: 'sign-up-create-account-button', + signInLink: 'sign-up-sign-in-link', + signUpButton: 'sign-up-sign-up-button', + signInButton: 'sign-up-sign-in-button', + confirmButton: 'sign-up-confirm-button', }; const verifyContact = { - section: 'verify-contact-section', - headerSection: 'verify-contact-header-section', - bodySection: 'verify-contact-body-section', - submitButton: 'verify-contact-submit-button', - verifyButton: 'verify-contact-verify-button', - skipLink: 'verify-contact-skip-link', + section: 'verify-contact-section', + headerSection: 'verify-contact-header-section', + bodySection: 'verify-contact-body-section', + submitButton: 'verify-contact-submit-button', + verifyButton: 'verify-contact-verify-button', + skipLink: 'verify-contact-skip-link', }; const TOTPSetup = { - component: 'totp-setup-component', + component: 'totp-setup-component', }; const requireNewPassword = { - section: 'require-new-password-section', - headerSection: 'require-new-password-header-section', - footerSection:'require-new-password-footer-section', - bodySection:'require-new-password-body-section', - newPasswordInput:'require-new-password-new-password-input', - backToSignInLink:'require-new-password-back-to-sign-in-link', - submitButton: 'require-new-password-submit-button', + section: 'require-new-password-section', + headerSection: 'require-new-password-header-section', + footerSection: 'require-new-password-footer-section', + bodySection: 'require-new-password-body-section', + newPasswordInput: 'require-new-password-new-password-input', + backToSignInLink: 'require-new-password-back-to-sign-in-link', + submitButton: 'require-new-password-submit-button', }; const loading = { - section: 'loading-secton', + section: 'loading-secton', }; const greetings = { - navBar: 'greetings-nav-bar', - nav: 'greetings-nav', - navRight: 'greetings-nav-right' + navBar: 'greetings-nav-bar', + nav: 'greetings-nav', + navRight: 'greetings-nav-right', }; -// TODO: Change Angular Component (Greeting) to match React Component (Greetings) +// TODO: Change Angular Component (Greeting) to match React Component (Greetings) const greeting = { - signOutButton: 'sign-out-button', - signOutLink: 'greeting-sign-out-link', - navRight: 'greetings-nav-right', + signOutButton: 'sign-out-button', + signOutLink: 'greeting-sign-out-link', + navRight: 'greetings-nav-right', }; const federatedSignIn = { - section: 'federated-sign-in-section', - bodySection: 'federated-sign-in-body-section', - signInButtons:'federated-sign-in-buttons', + section: 'federated-sign-in-section', + bodySection: 'federated-sign-in-body-section', + signInButtons: 'federated-sign-in-buttons', }; const confirmSignUp = { - section: 'confirm-sign-up-section', - headerSection: 'confirm-sign-up-header-section', - bodySection: 'confirm-sign-up-body-section', - usernameInput: 'confirm-sign-up-username-input', - confirmationCodeInput: 'confirm-sign-up-confirmation-code-input', - resendCodeLink: 'confirm-sign-up-resend-code-link', - confirmButton: 'confirm-sign-up-confirm-button', - backToSignInLink: 'confirm-sign-up-back-to-sign-in-link' + section: 'confirm-sign-up-section', + headerSection: 'confirm-sign-up-header-section', + bodySection: 'confirm-sign-up-body-section', + usernameInput: 'confirm-sign-up-username-input', + confirmationCodeInput: 'confirm-sign-up-confirmation-code-input', + resendCodeLink: 'confirm-sign-up-resend-code-link', + confirmButton: 'confirm-sign-up-confirm-button', + backToSignInLink: 'confirm-sign-up-back-to-sign-in-link', }; const confirmSignIn = { - section: 'confirm-sign-in-section', - headerSection: 'confirm-sign-in-header-section', - bodySection: 'confirm-sign-in-body-section', - codeInput: 'confirm-sign-in-code-input', - confirmButton: 'confirm-sign-in-confirm-button', - backToSignInLink: 'confirm-sign-in-back-to-sign-in-link', + section: 'confirm-sign-in-section', + headerSection: 'confirm-sign-in-header-section', + bodySection: 'confirm-sign-in-body-section', + codeInput: 'confirm-sign-in-code-input', + confirmButton: 'confirm-sign-in-confirm-button', + backToSignInLink: 'confirm-sign-in-back-to-sign-in-link', }; const setMFAComp = { - section: 'set-mfa-section', - headerSection: 'set-mfa-header-section', - bodySection: 'set-mfa-header-body-section', - smsInput: 'set-mfa-sms-input', - totpInput: 'set-mfa-totp-input', - noMfaInput: 'set-mfa-nomfa-input', - verificationCodeInput: 'set-mfa-verification-code-input', - setMfaButton: 'set-mfa-set-mfa-button', - verifyTotpTokenButton: 'set-mfa-verify-totp-token-button', - cancelButton: 'set-mfa-cancel-button', + section: 'set-mfa-section', + headerSection: 'set-mfa-header-section', + bodySection: 'set-mfa-header-body-section', + smsInput: 'set-mfa-sms-input', + totpInput: 'set-mfa-totp-input', + noMfaInput: 'set-mfa-nomfa-input', + verificationCodeInput: 'set-mfa-verification-code-input', + setMfaButton: 'set-mfa-set-mfa-button', + verifyTotpTokenButton: 'set-mfa-verify-totp-token-button', + cancelButton: 'set-mfa-cancel-button', }; const forgotPassword = { - section: 'forgot-password-section', - headerSection: 'forgot-password-header-section', - bodySection: 'forgot-password-body-section', - submitButton: 'forgot-password-submit-button', - sendCodeButton: 'forgot-password-send-code-button', - resendCodeLink: 'forgot-password-resend-code-link', - backToSignInLink: 'forgot-password-back-to-sign-in-link', - usernameInput: 'username-input', - codeInput: 'forgot-password-code-input', - newPasswordInput: 'forgot-password-new-password-input', + section: 'forgot-password-section', + headerSection: 'forgot-password-header-section', + bodySection: 'forgot-password-body-section', + submitButton: 'forgot-password-submit-button', + sendCodeButton: 'forgot-password-send-code-button', + resendCodeLink: 'forgot-password-resend-code-link', + backToSignInLink: 'forgot-password-back-to-sign-in-link', + usernameInput: 'username-input', + codeInput: 'forgot-password-code-input', + newPasswordInput: 'forgot-password-new-password-input', }; export const sumerianScene = { - container: 'sumerian-scene-container', - sumerianScene: 'sumerian-scene', - loading: 'sumerian-scene-loading', - loadingLogo: 'sumerian-scene-loading-logo', - loadingSceneName: 'sumerian-scene-loading-scene-name', - loadingBar: 'sumerian-scene-loading-bar', - errorText: 'sumerian-scene-error-text', - bar: 'sumerian-scene-bar', - actions: 'sumerian-scene-actions', + container: 'sumerian-scene-container', + sumerianScene: 'sumerian-scene', + loading: 'sumerian-scene-loading', + loadingLogo: 'sumerian-scene-loading-logo', + loadingSceneName: 'sumerian-scene-loading-scene-name', + loadingBar: 'sumerian-scene-loading-bar', + errorText: 'sumerian-scene-error-text', + bar: 'sumerian-scene-bar', + actions: 'sumerian-scene-actions', }; export const genericAttrs = { - usernameInput: 'username-input', - emailInput: 'email-input', - phoneNumberInput: 'phone-number-input', - dialCodeSelect: 'dial-code-select', + usernameInput: 'username-input', + emailInput: 'email-input', + phoneNumberInput: 'phone-number-input', + dialCodeSelect: 'dial-code-select', }; - export const auth = { - signIn, - signOut, - signUp, - verifyContact, - TOTPSetup, - requireNewPassword, - loading, - genericAttrs, - greetings, - greeting, - federatedSignIn, - confirmSignUp, - confirmSignIn, - setMFAComp, - forgotPassword, + signIn, + signOut, + signUp, + verifyContact, + TOTPSetup, + requireNewPassword, + loading, + genericAttrs, + greetings, + greeting, + federatedSignIn, + confirmSignUp, + confirmSignIn, + setMFAComp, + forgotPassword, }; diff --git a/packages/aws-amplify-angular/src/assets/default-sign-up-fields.ts b/packages/aws-amplify-angular/src/assets/default-sign-up-fields.ts index da1f5427a27..33462f419b6 100644 --- a/packages/aws-amplify-angular/src/assets/default-sign-up-fields.ts +++ b/packages/aws-amplify-angular/src/assets/default-sign-up-fields.ts @@ -13,76 +13,76 @@ */ // tslint:enable export default [ - { - label: 'Username', - key: 'username', - required: false, - displayOrder: 1 - }, - { - label: 'Password', - key: 'password', - required: true, - type: 'password', - displayOrder: 2, - }, - { - label: 'Email', - key: 'email', - required: true, - type: 'email', - displayOrder: 3 - }, - { - label: 'Phone Number', - key: 'phone_number', - required: true, - displayOrder: 4 - } + { + label: 'Username', + key: 'username', + required: false, + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + type: 'password', + displayOrder: 2, + }, + { + label: 'Email', + key: 'email', + required: true, + type: 'email', + displayOrder: 3, + }, + { + label: 'Phone Number', + key: 'phone_number', + required: true, + displayOrder: 4, + }, ]; export const signUpWithEmailFields = [ - { - label: 'Email', - key: 'email', - required: true, - type: 'email', - displayOrder: 1, - }, - { - label: 'Password', - key: 'password', - required: true, - type: 'password', - displayOrder: 2, - }, - { - label: 'Phone Number', - key: 'phone_number', - required: true, - displayOrder: 3 - } + { + label: 'Email', + key: 'email', + required: true, + type: 'email', + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + type: 'password', + displayOrder: 2, + }, + { + label: 'Phone Number', + key: 'phone_number', + required: true, + displayOrder: 3, + }, ]; - export const signUpWithPhoneNumberFields = [ - { - label: 'Phone Number', - key: 'phone_number', - required: true, - displayOrder: 1, - }, - { - label: 'Password', - key: 'password', - required: true, - type: 'password', - displayOrder: 2, - }, - { - label: 'Email', - key: 'email', - required: true, - type: 'email', - displayOrder: 3 - }, -]; \ No newline at end of file +export const signUpWithPhoneNumberFields = [ + { + label: 'Phone Number', + key: 'phone_number', + required: true, + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + type: 'password', + displayOrder: 2, + }, + { + label: 'Email', + key: 'email', + required: true, + type: 'email', + displayOrder: 3, + }, +]; diff --git a/packages/aws-amplify-angular/src/aws-amplify-angular.module.ts b/packages/aws-amplify-angular/src/aws-amplify-angular.module.ts index a62e82824f7..6315c5499be 100644 --- a/packages/aws-amplify-angular/src/aws-amplify-angular.module.ts +++ b/packages/aws-amplify-angular/src/aws-amplify-angular.module.ts @@ -11,8 +11,7 @@ * and limitations under the License. */ - -import { NgModule , forwardRef} from '@angular/core'; +import { NgModule, forwardRef } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; @@ -42,7 +41,7 @@ import { S3ImageComponentCore } from './components/storage/s3-image-component/s3 import { PhotoPickerComponent } from './components/storage/photo-picker-component/photo-picker.factory'; import { PhotoPickerComponentCore } from './components/storage/photo-picker-component/photo-picker.component.core'; import { ChatBotComponent } from './components/interactions/chatbot/chatbot.factory'; -import { ChatbotComponentCore } from './components/interactions/chatbot/chatbot.component.core'; +import { ChatbotComponentCore } from './components/interactions/chatbot/chatbot.component.core'; import { DynamicComponentDirective } from './directives/dynamic.component.directive'; import { FormComponent } from './components/common/form.component'; import { SumerianSceneComponent } from './components/xr/sumerian-scene-component/sumerian-scene.factory'; @@ -51,53 +50,43 @@ import { SumerianSceneLoadingComponentCore } from './components/xr/sumerian-scen // tslint:enable:max-line-length const components = [ - AuthenticatorComponent, - AuthenticatorComponentCore, - ConfirmSignInComponent, - ConfirmSignInComponentCore, - ConfirmSignUpComponent, - ConfirmSignUpComponentCore, - SignInComponent, - SignInComponentCore, - SignUpComponent, - SignUpComponentCore, - RequireNewPasswordComponent, - RequireNewPasswordComponentCore, - GreetingComponent, - GreetingComponentCore, - ForgotPasswordComponent, - ForgotPasswordComponentCore, - UsernameFieldComponentCore, - PhoneFieldComponentCore, - S3AlbumComponent, - S3AlbumComponentCore, - S3ImageComponent, - S3ImageComponentCore, - PhotoPickerComponent, - PhotoPickerComponentCore, - ChatBotComponent, - ChatbotComponentCore, - FormComponent, - SumerianSceneComponent, - SumerianSceneComponentCore, - SumerianSceneLoadingComponentCore + AuthenticatorComponent, + AuthenticatorComponentCore, + ConfirmSignInComponent, + ConfirmSignInComponentCore, + ConfirmSignUpComponent, + ConfirmSignUpComponentCore, + SignInComponent, + SignInComponentCore, + SignUpComponent, + SignUpComponentCore, + RequireNewPasswordComponent, + RequireNewPasswordComponentCore, + GreetingComponent, + GreetingComponentCore, + ForgotPasswordComponent, + ForgotPasswordComponentCore, + UsernameFieldComponentCore, + PhoneFieldComponentCore, + S3AlbumComponent, + S3AlbumComponentCore, + S3ImageComponent, + S3ImageComponentCore, + PhotoPickerComponent, + PhotoPickerComponentCore, + ChatBotComponent, + ChatbotComponentCore, + FormComponent, + SumerianSceneComponent, + SumerianSceneComponentCore, + SumerianSceneLoadingComponentCore, ]; @NgModule({ - imports: [ - CommonModule, - FormsModule, - ], - declarations: [ - DynamicComponentDirective, - ...components, - ], - entryComponents: [ - ...components - ], - providers: [ ], - exports: [ - ...components, - ] + imports: [CommonModule, FormsModule], + declarations: [DynamicComponentDirective, ...components], + entryComponents: [...components], + providers: [], + exports: [...components], }) -export class AmplifyAngularModule { } +export class AmplifyAngularModule {} diff --git a/packages/aws-amplify-angular/src/aws-amplify-ionic-module.ts b/packages/aws-amplify-angular/src/aws-amplify-ionic-module.ts index 4c6cfe29a8e..5b0a5a4cbeb 100644 --- a/packages/aws-amplify-angular/src/aws-amplify-ionic-module.ts +++ b/packages/aws-amplify-angular/src/aws-amplify-ionic-module.ts @@ -37,39 +37,30 @@ import { SumerianSceneLoadingComponentIonic } from './components/xr/sumerian-sce // tslint:enable:max-line-length const components = [ - AuthenticatorIonicComponent, - ConfirmSignInComponentIonic, - ConfirmSignUpComponentIonic, - ForgotPasswordComponentIonic, - GreetingComponentIonic, - SignInComponentIonic, - SignUpComponentIonic, - UsernameFieldComponentIonic, - PhoneFieldComponentIonic, - RequireNewPasswordComponentIonic, - PhotoPickerIonicComponent, - S3AlbumComponentIonic, - S3ImageComponentIonic, - ChatbotComponentIonic, - SumerianSceneComponentIonic, - SumerianSceneLoadingComponentIonic + AuthenticatorIonicComponent, + ConfirmSignInComponentIonic, + ConfirmSignUpComponentIonic, + ForgotPasswordComponentIonic, + GreetingComponentIonic, + SignInComponentIonic, + SignUpComponentIonic, + UsernameFieldComponentIonic, + PhoneFieldComponentIonic, + RequireNewPasswordComponentIonic, + PhotoPickerIonicComponent, + S3AlbumComponentIonic, + S3ImageComponentIonic, + ChatbotComponentIonic, + SumerianSceneComponentIonic, + SumerianSceneLoadingComponentIonic, ]; @NgModule({ - imports: [ - CommonModule, - FormsModule - ], - declarations: [ - ...components, - ], - entryComponents: [ - ...components - ], - providers: [AmplifyService], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - exports: [ - ...components - ] + imports: [CommonModule, FormsModule], + declarations: [...components], + entryComponents: [...components], + providers: [AmplifyService], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + exports: [...components], }) -export class AmplifyIonicModule { } +export class AmplifyIonicModule {} diff --git a/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.class.ts b/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.class.ts index 7a9cce0944f..4f66d39a5a3 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.class.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.class.ts @@ -14,5 +14,5 @@ // tslint:enable export class AuthClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.component.core.ts b/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.component.core.ts index e7407c8e8ed..fe2919221b9 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.component.core.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.component.core.ts @@ -68,80 +68,82 @@ const template = ` `; @Component({ - selector: 'amplify-authenticator-core', - template + selector: 'amplify-authenticator-core', + template, }) export class AuthenticatorComponentCore implements OnInit { - authState: AuthState = { - state: 'loading', - user: null - }; - _signUpConfig: any = {}; - _usernameAttributes: string = 'username'; - - constructor(protected amplifyService: AmplifyService) { - this.subscribe(); - } - - ngOnInit() { - if (!this.amplifyService.auth()){ - throw new Error('Auth module not registered on AmplifyService provider'); - } else { - const loadStatus = this.amplifyService.auth().currentAuthenticatedUser() - .then((user) => { - if (this.authState.state === 'loading' && user) { - this.amplifyService.setAuthState({ state: 'signedIn', user }); - } - }) - .catch((e) => { - if (this.authState.state === 'loading') { - this.amplifyService.setAuthState({ state: 'signIn', user: null }); - } - }); - } - } - - @Input() - hide: string[] = []; - - @Input() - set data(data: any) { - if (data.signUpConfig) { - this._signUpConfig = data.signUpConfig; - } - if (data.hide) { - this.hide = data.hide; - } - - this._usernameAttributes = data.usernameAttributes || this._usernameAttributes || 'username'; - } - - @Input() - set signUpConfig(signUpConfig: any) { - this._signUpConfig = signUpConfig; - } - - @Input() - set usernameAttributes(usernameAttributes: string) { - this._usernameAttributes = usernameAttributes || 'username'; - } - - subscribe() { - this.amplifyService.authStateChange$ - .subscribe( - state => { - this.authState = state; - }, - () => { - this.authState = { - 'state': 'signIn', - 'user': null - }; - }); - } - - shouldHide(comp) { - return this.hide.filter(item => item === comp) - .length > 0; - } + authState: AuthState = { + state: 'loading', + user: null, + }; + _signUpConfig: any = {}; + _usernameAttributes: string = 'username'; + + constructor(protected amplifyService: AmplifyService) { + this.subscribe(); + } + + ngOnInit() { + if (!this.amplifyService.auth()) { + throw new Error('Auth module not registered on AmplifyService provider'); + } else { + const loadStatus = this.amplifyService + .auth() + .currentAuthenticatedUser() + .then(user => { + if (this.authState.state === 'loading' && user) { + this.amplifyService.setAuthState({ state: 'signedIn', user }); + } + }) + .catch(e => { + if (this.authState.state === 'loading') { + this.amplifyService.setAuthState({ state: 'signIn', user: null }); + } + }); + } + } + + @Input() + hide: string[] = []; + + @Input() + set data(data: any) { + if (data.signUpConfig) { + this._signUpConfig = data.signUpConfig; + } + if (data.hide) { + this.hide = data.hide; + } + + this._usernameAttributes = + data.usernameAttributes || this._usernameAttributes || 'username'; + } + + @Input() + set signUpConfig(signUpConfig: any) { + this._signUpConfig = signUpConfig; + } + + @Input() + set usernameAttributes(usernameAttributes: string) { + this._usernameAttributes = usernameAttributes || 'username'; + } + + subscribe() { + this.amplifyService.authStateChange$.subscribe( + state => { + this.authState = state; + }, + () => { + this.authState = { + state: 'signIn', + user: null, + }; + } + ); + } + + shouldHide(comp) { + return this.hide.filter(item => item === comp).length > 0; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.component.ionic.ts b/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.component.ionic.ts index 6e913b905d6..4e006443766 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.component.ionic.ts @@ -13,7 +13,13 @@ */ // tslint:enable -import { Component, Input, ViewEncapsulation, Injector, ElementRef } from '@angular/core'; +import { + Component, + Input, + ViewEncapsulation, + Injector, + ElementRef, +} from '@angular/core'; import { AmplifyService, AuthState } from '../../../providers'; import { AuthenticatorComponentCore } from './authenticator.component.core'; @@ -71,12 +77,11 @@ const template = ` `; @Component({ - selector: 'amplify-authenticator-ionic', - template + selector: 'amplify-authenticator-ionic', + template, }) export class AuthenticatorIonicComponent extends AuthenticatorComponentCore { - - constructor(protected amplifyService: AmplifyService) { - super(amplifyService); - } + constructor(protected amplifyService: AmplifyService) { + super(amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.factory.ts b/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.factory.ts index 3fb9f23d452..17a7ee3a486 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.factory.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/authenticator/authenticator.factory.ts @@ -14,68 +14,66 @@ // tslint:enable import { - Component, - Input, - OnInit, - ViewChild, - ComponentFactoryResolver, - OnDestroy + Component, + Input, + OnInit, + ViewChild, + ComponentFactoryResolver, + OnDestroy, } from '@angular/core'; import { DynamicComponentDirective } from '../../../directives/dynamic.component.directive'; -import { ComponentMount } from '../../component.mount'; +import { ComponentMount } from '../../component.mount'; import { AuthClass } from './authenticator.class'; import { AuthenticatorIonicComponent } from './authenticator.component.ionic'; import { AuthenticatorComponentCore } from './authenticator.component.core'; @Component({ - selector: 'amplify-authenticator', - template: ` -
- -
- ` + selector: 'amplify-authenticator', + template: ` +
+ +
+ `, }) export class AuthenticatorComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() hide: string[] = []; - @Input() signUpConfig: any; - @Input() usernameAttributes: string = 'username'; - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; + @Input() framework: string; + @Input() hide: string[] = []; + @Input() signUpConfig: any; + @Input() usernameAttributes: string = 'username'; + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnInit() { - this.loadComponent(); - } + ngOnInit() { + this.loadComponent(); + } - ngOnDestroy() {} + ngOnDestroy() {} - loadComponent() { + loadComponent() { + const authComponent = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(AuthenticatorIonicComponent, { + hide: this.hide, + signUpConfig: this.signUpConfig, + usernameAttributes: this.usernameAttributes, + }) + : new ComponentMount(AuthenticatorComponentCore, { + hide: this.hide, + signUpConfig: this.signUpConfig, + usernameAttributes: this.usernameAttributes, + }); - const authComponent = this.framework && this.framework.toLowerCase() === 'ionic' ? - new ComponentMount( - AuthenticatorIonicComponent, - { - hide: this.hide, - signUpConfig: this.signUpConfig, - usernameAttributes: this.usernameAttributes - }) - : - new ComponentMount( - AuthenticatorComponentCore, { - hide: this.hide, - signUpConfig: this.signUpConfig, - usernameAttributes: this.usernameAttributes - }); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + authComponent.component + ); - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(authComponent.component); + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); - - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = authComponent.data; - } + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = authComponent.data; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/common.ts b/packages/aws-amplify-angular/src/components/authenticator/common.ts index 92287e60b73..c3dd3c6b3a1 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/common.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/common.ts @@ -14,15 +14,15 @@ // tslint:enable export function includes(ary, match) { - return ary.filter(item => item === match).length > 0; + return ary.filter(item => item === match).length > 0; } export const labelMap = { - email: 'Email', - phone_number: 'Phone Number', - username: 'Username' + email: 'Email', + phone_number: 'Phone Number', + username: 'Username', }; export const composePhoneNumber = (countryCode, local_phone_number) => { - return `+${countryCode}${local_phone_number.replace(/[-()]/g, '')}`; -} \ No newline at end of file + return `+${countryCode}${local_phone_number.replace(/[-()]/g, '')}`; +}; diff --git a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in-component.core.ts b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in-component.core.ts index 838f23711ba..328e5fd2de2 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in-component.core.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in-component.core.ts @@ -71,82 +71,81 @@ const template = ` `; @Component({ - selector: 'amplify-auth-confirm-sign-in-core', - template + selector: 'amplify-auth-confirm-sign-in-core', + template, }) export class ConfirmSignInComponentCore implements OnInit { - _authState: AuthState; - _show: boolean; - code: string; - errorMessage: string; - protected logger: any; + _authState: AuthState; + _show: boolean; + code: string; + errorMessage: string; + protected logger: any; - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - this.logger = this.amplifyService.logger('ConfiSignInComponent'); - } + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + this.logger = this.amplifyService.logger('ConfiSignInComponent'); + } - @Input() - set data(data: any) { - this.hide = data.hide ? data.hide : this.hide; - this._authState = data.authState; - this._show = data.authState.state === 'confirmSignIn'; - } + @Input() + set data(data: any) { + this.hide = data.hide ? data.hide : this.hide; + this._authState = data.authState; + this._show = data.authState.state === 'confirmSignIn'; + } - @Input() - set authState(authState: AuthState) { - this._authState = authState; - this._show = authState.state === 'confirmSignIn'; - } + @Input() + set authState(authState: AuthState) { + this._authState = authState; + this._show = authState.state === 'confirmSignIn'; + } - @Input() hide: string[] = []; + @Input() hide: string[] = []; - ngOnInit() { - if (!this.amplifyService.auth()){ - throw new Error('Auth module not registered on AmplifyService provider'); - } - } + ngOnInit() { + if (!this.amplifyService.auth()) { + throw new Error('Auth module not registered on AmplifyService provider'); + } + } - shouldHide(comp) { - return this.hide.filter(item => item === comp) - .length > 0; - } + shouldHide(comp) { + return this.hide.filter(item => item === comp).length > 0; + } - setCode(code: string) { - this.code = code; - } + setCode(code: string) { + this.code = code; + } - onConfirm() { - const { user } = this._authState; - const { challengeName } = user; - const mfaType = challengeName === 'SOFTWARE_TOKEN_MFA' ? challengeName : null; - this.amplifyService.auth() - .confirmSignIn( - user, - this.code, - mfaType - ) - .then(() => { - this.onAlertClose(); - this.amplifyService.setAuthState({ state: 'signedIn', user }); - }) - .catch(err => this._setError(err)); - } + onConfirm() { + const { user } = this._authState; + const { challengeName } = user; + const mfaType = + challengeName === 'SOFTWARE_TOKEN_MFA' ? challengeName : null; + this.amplifyService + .auth() + .confirmSignIn(user, this.code, mfaType) + .then(() => { + this.onAlertClose(); + this.amplifyService.setAuthState({ state: 'signedIn', user }); + }) + .catch(err => this._setError(err)); + } - onSignIn() { - this.onAlertClose(); - this.amplifyService.setAuthState({ state: 'signIn', user: null }); - } + onSignIn() { + this.onAlertClose(); + this.amplifyService.setAuthState({ state: 'signIn', user: null }); + } - onAlertClose() { - this._setError(null); - } + onAlertClose() { + this._setError(null); + } - _setError(err) { - if (!err) { - this.errorMessage = null; - return; - } + _setError(err) { + if (!err) { + this.errorMessage = null; + return; + } - this.errorMessage = err.message || err; - } + this.errorMessage = err.message || err; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in-component.ionic.ts b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in-component.ionic.ts index 9ca9639b6d8..ea8911bd4f6 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in-component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in-component.ionic.ts @@ -51,16 +51,18 @@ const template = ` `; @Component({ - selector: 'amplify-auth-confirm-sign-in-ionic', - template + selector: 'amplify-auth-confirm-sign-in-ionic', + template, }) export class ConfirmSignInComponentIonic extends ConfirmSignInComponentCore { - _authState: AuthState; - _show: boolean; - code: string; - errorMessage: string; + _authState: AuthState; + _show: boolean; + code: string; + errorMessage: string; - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - super(amplifyService); - } + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + super(amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in.class.ts b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in.class.ts index 6ce5cb5e0c7..0eed86cc77b 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in.class.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in.class.ts @@ -14,5 +14,5 @@ // tslint:enable export class ConfirmSignInClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in.factory.ts b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in.factory.ts index d2efc71d6d5..343a420372b 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in.factory.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-in-component/confirm-sign-in.factory.ts @@ -14,56 +14,63 @@ // tslint:enable import { - Component, - Input, - OnInit, - ViewChild, - ComponentFactoryResolver, - OnDestroy + Component, + Input, + OnInit, + ViewChild, + ComponentFactoryResolver, + OnDestroy, } from '@angular/core'; import { DynamicComponentDirective } from '../../../directives/dynamic.component.directive'; -import { ComponentMount } from '../../component.mount'; +import { ComponentMount } from '../../component.mount'; import { ConfirmSignInClass } from './confirm-sign-in.class'; import { ConfirmSignInComponentIonic } from './confirm-sign-in-component.ionic'; import { ConfirmSignInComponentCore } from './confirm-sign-in-component.core'; import { AuthState } from '../../../providers'; - @Component({ - selector: 'amplify-auth-confirm-sign-in', - template: ` -
- -
- ` + selector: 'amplify-auth-confirm-sign-in', + template: ` +
+ +
+ `, }) export class ConfirmSignInComponent implements OnInit, OnDestroy { - @Input() framework: String; - @Input() authState: AuthState; - @Input() hide: string[] = []; - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; - - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + @Input() framework: String; + @Input() authState: AuthState; + @Input() hide: string[] = []; + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - ngOnInit() { - this.loadComponent(); - } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnDestroy() {} + ngOnInit() { + this.loadComponent(); + } - loadComponent() { + ngOnDestroy() {} - const authComponent = this.framework && this.framework.toLowerCase() === 'ionic' ? - new ComponentMount(ConfirmSignInComponentIonic,{authState: this.authState, hide: this.hide}) : - new ComponentMount(ConfirmSignInComponentCore, {authState: this.authState, hide: this.hide}); + loadComponent() { + const authComponent = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(ConfirmSignInComponentIonic, { + authState: this.authState, + hide: this.hide, + }) + : new ComponentMount(ConfirmSignInComponentCore, { + authState: this.authState, + hide: this.hide, + }); - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(authComponent.component); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + authComponent.component + ); - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = authComponent.data; - } + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = authComponent.data; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.class.ts b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.class.ts index 1919dc8e5b9..f3fb11ca6f6 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.class.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.class.ts @@ -14,5 +14,5 @@ // tslint:enable export class ConfirmSignUpClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.component.core.ts b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.component.core.ts index 29e0935a86c..e8d866383a3 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.component.core.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.component.core.ts @@ -94,99 +94,103 @@ const template = ` `; @Component({ - selector: 'amplify-auth-confirm-sign-up-core', - template + selector: 'amplify-auth-confirm-sign-up-core', + template, }) - export class ConfirmSignUpComponentCore implements OnInit { - _authState: AuthState; - _show: boolean; - _usernameAttributes: string = 'username'; - username: string; - code: string; - errorMessage: string; - protected logger: any; - - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - this.logger = this.amplifyService.logger('ConfirmSignUpComponent'); - } - - @Input() - set data(data: any) { - this.hide = data.hide ? data.hide : this.hide; - this._authState = data.authState; - this._show = data.authState.state === 'confirmSignUp'; - this.username = data.authState.user? data.authState.user.username || '' : ''; - } - - @Input() hide: string[] = []; - - @Input() - set authState(authState: AuthState) { - this._authState = authState; - this._show = authState.state === 'confirmSignUp'; - - this.username = authState.user? authState.user.username || '' : ''; - } - - @Input() - set usernameAttributes(usernameAttributes: string) { - this._usernameAttributes = usernameAttributes; - } - - ngOnInit() { - if (!this.amplifyService.auth()){ - throw new Error('Auth module not registered on AmplifyService provider'); - } - } - shouldHide(comp) { - return this.hide.filter(item => item === comp) - .length > 0; - } - - setUsername(username: string) { - this.username = username; - } - - setCode(code: string) { - this.code = code; - } - - onConfirm() { - this.amplifyService.auth() - .confirmSignUp( - this.username, - this.code - ) - .then(() => this.logger.info('confirm success')) - .catch(err => this._setError(err)); - } - - onResend() { - this.amplifyService.auth().resendSignUp(this.username) - .then(() => this.logger.info('code resent')) - .catch(err => this._setError(err)); - } - - onSignIn() { - this.onAlertClose(); - this.amplifyService.setAuthState({ state: 'signIn', user: null }); - } - - onAlertClose() { - this._setError(null); - } - - _setError(err) { - if (!err) { - this.errorMessage = null; - return; - } - - this.errorMessage = err.message || err; - } - - getUsernameLabel() { - return labelMap[this._usernameAttributes as string] || this._usernameAttributes; - } + _authState: AuthState; + _show: boolean; + _usernameAttributes: string = 'username'; + username: string; + code: string; + errorMessage: string; + protected logger: any; + + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + this.logger = this.amplifyService.logger('ConfirmSignUpComponent'); + } + + @Input() + set data(data: any) { + this.hide = data.hide ? data.hide : this.hide; + this._authState = data.authState; + this._show = data.authState.state === 'confirmSignUp'; + this.username = data.authState.user + ? data.authState.user.username || '' + : ''; + } + + @Input() hide: string[] = []; + + @Input() + set authState(authState: AuthState) { + this._authState = authState; + this._show = authState.state === 'confirmSignUp'; + + this.username = authState.user ? authState.user.username || '' : ''; + } + + @Input() + set usernameAttributes(usernameAttributes: string) { + this._usernameAttributes = usernameAttributes; + } + + ngOnInit() { + if (!this.amplifyService.auth()) { + throw new Error('Auth module not registered on AmplifyService provider'); + } + } + shouldHide(comp) { + return this.hide.filter(item => item === comp).length > 0; + } + + setUsername(username: string) { + this.username = username; + } + + setCode(code: string) { + this.code = code; + } + + onConfirm() { + this.amplifyService + .auth() + .confirmSignUp(this.username, this.code) + .then(() => this.logger.info('confirm success')) + .catch(err => this._setError(err)); + } + + onResend() { + this.amplifyService + .auth() + .resendSignUp(this.username) + .then(() => this.logger.info('code resent')) + .catch(err => this._setError(err)); + } + + onSignIn() { + this.onAlertClose(); + this.amplifyService.setAuthState({ state: 'signIn', user: null }); + } + + onAlertClose() { + this._setError(null); + } + + _setError(err) { + if (!err) { + this.errorMessage = null; + return; + } + + this.errorMessage = err.message || err; + } + + getUsernameLabel() { + return ( + labelMap[this._usernameAttributes as string] || this._usernameAttributes + ); + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.component.ionic.ts b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.component.ionic.ts index 75155f6c651..0c411094f6b 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.component.ionic.ts @@ -107,12 +107,13 @@ const template = ` `; @Component({ - selector: 'amplify-auth-confirm-sign-up-ionic', - template + selector: 'amplify-auth-confirm-sign-up-ionic', + template, }) export class ConfirmSignUpComponentIonic extends ConfirmSignUpComponentCore { - - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - super(amplifyService); - } + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + super(amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.factory.ts b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.factory.ts index 2ea98234247..e3c78a382ef 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.factory.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/confirm-sign-up-component/confirm-sign-up.factory.ts @@ -14,55 +14,66 @@ // tslint:enable import { - Component, - Input, OnInit, - ViewChild, - ComponentFactoryResolver, - OnDestroy + Component, + Input, + OnInit, + ViewChild, + ComponentFactoryResolver, + OnDestroy, } from '@angular/core'; import { DynamicComponentDirective } from '../../../directives/dynamic.component.directive'; -import { ComponentMount } from '../../component.mount'; +import { ComponentMount } from '../../component.mount'; import { ConfirmSignUpClass } from './confirm-sign-up.class'; import { ConfirmSignUpComponentIonic } from './confirm-sign-up.component.ionic'; import { ConfirmSignUpComponentCore } from './confirm-sign-up.component.core'; import { AuthState } from '../../../providers'; @Component({ - selector: 'amplify-auth-confirm-sign-up', - template: ` -
- -
- ` + selector: 'amplify-auth-confirm-sign-up', + template: ` +
+ +
+ `, }) export class ConfirmSignUpComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() authState: AuthState; - @Input() usernameAttributes: string = 'username'; - @Input() hide: string[] = []; - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; + @Input() framework: string; + @Input() authState: AuthState; + @Input() usernameAttributes: string = 'username'; + @Input() hide: string[] = []; + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnInit() { - this.loadComponent(); - } + ngOnInit() { + this.loadComponent(); + } - ngOnDestroy() {} + ngOnDestroy() {} - loadComponent() { + loadComponent() { + const authComponent = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(ConfirmSignUpComponentIonic, { + authState: this.authState, + usernameAttributes: this.usernameAttributes, + hide: this.hide, + }) + : new ComponentMount(ConfirmSignUpComponentCore, { + authState: this.authState, + usernameAttributes: this.usernameAttributes, + hide: this.hide, + }); - const authComponent = this.framework && this.framework.toLowerCase() === 'ionic' ? - new ComponentMount(ConfirmSignUpComponentIonic,{authState: this.authState, usernameAttributes: this.usernameAttributes, hide: this.hide}) : - new ComponentMount(ConfirmSignUpComponentCore, {authState: this.authState, usernameAttributes: this.usernameAttributes, hide: this.hide}); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + authComponent.component + ); - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(authComponent.component); + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); - - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = authComponent.data; - } + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = authComponent.data; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.class.ts b/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.class.ts index 1536dba2693..191fb3dcc94 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.class.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.class.ts @@ -14,5 +14,5 @@ // tslint:enable export class ForgotPasswordClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.component.core.ts b/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.component.core.ts index 1db2182d311..3a7f22460f7 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.component.core.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.component.core.ts @@ -111,144 +111,160 @@ const template = ` `; @Component({ - selector: 'amplify-auth-forgot-password-core', - template + selector: 'amplify-auth-forgot-password-core', + template, }) export class ForgotPasswordComponentCore implements OnInit { - _authState: AuthState; - _show: boolean; - _usernameAttributes: string = 'username'; - username: string; - code: string; - password: string; - errorMessage: string; - code_sent = false; - protected logger: any; - local_phone_number: string; - country_code: string = '1'; - email: string; - - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - this.logger = this.amplifyService.logger('ForgotPasswordComponent'); - } - - @Input() - set data(data: any) { - this._authState = data.authState; - this._show = data.authState.state === 'forgotPassword'; - this._usernameAttributes = data.usernameAttributes; - this.hide = data.hide ? data.hide : this.hide; - - this.username = (data.authState.user && - data.authState.user.username) ? - data.authState.user.username : ''; - } - - @Input() hide: string[] = []; - - shouldHide(comp) { - return this.hide.filter(item => item === comp) - .length > 0; - } - - @Input() - set authState(authState: AuthState) { - this._authState = authState; - this._show = authState.state === 'forgotPassword'; - - this.email = (authState.user && authState.user.email)? authState.user.email : ''; - this.country_code = (authState.user && authState.user.contry_code) ? authState.user.country_code : '1'; - this.local_phone_number = (authState.user && authState.user.local_phone_number) ? authState.user.local_phone_number : ''; - this.username = (authState.user && authState.user.username) ? authState.user.username : ''; - } - - ngOnInit() { - if (!this.amplifyService.auth()){ - throw new Error('Auth module not registered on AmplifyService provider'); - } - } - - @Input() - set usernameAttributes(usernameAttributes: string) { - this._usernameAttributes = usernameAttributes; - } - - setCode(code: string) { - this.code = code; - } - - setPassword(password: string) { - this.password = password; - } - - getforgotPwUsername() { - switch(this._usernameAttributes) { - case UsernameAttributes.EMAIL: - return this.email; - case UsernameAttributes.PHONE_NUMBER: - return composePhoneNumber(this.country_code, this.local_phone_number); - default: - return this.username; - } - } - - onSend() { - let forgotPwUsername = this.getforgotPwUsername(); - if (!forgotPwUsername) { - this.errorMessage = "Username cannot be empty"; - return; - } - this.amplifyService.auth().forgotPassword(forgotPwUsername) - .then(() => { - this.code_sent = true; - }) - .catch((err) => { - this._setError(err); - this.code_sent = false; - }); - } - - onSubmit() { - this.amplifyService.auth() - .forgotPasswordSubmit( - this.getforgotPwUsername(), - this.code, - this.password - ) - .then(() => { - const user = { username: this.username }; - this.onAlertClose(); - this.amplifyService.setAuthState({ state: 'signIn', user }); - }) - .catch(err => this._setError(err)); - } - - onSignIn() { - this.onAlertClose(); - this.amplifyService.setAuthState({ state: 'signIn', user: null }); - } - - onAlertClose() { - this._setError(null); - } - - _setError(err) { - if (!err) { - this.errorMessage = null; - return; - } - - this.errorMessage = err.message || err; - } - - getUsernameLabel() { - return labelMap[this._usernameAttributes as string] || this._usernameAttributes; - } - - onUsernameFieldChanged(event: UsernameFieldOutput) { - this.email = event.email || this.email; - this.username = event.username || this.username; - this.country_code = event.country_code || this.country_code; - this.local_phone_number = event.local_phone_number || this.local_phone_number; - } + _authState: AuthState; + _show: boolean; + _usernameAttributes: string = 'username'; + username: string; + code: string; + password: string; + errorMessage: string; + code_sent = false; + protected logger: any; + local_phone_number: string; + country_code: string = '1'; + email: string; + + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + this.logger = this.amplifyService.logger('ForgotPasswordComponent'); + } + + @Input() + set data(data: any) { + this._authState = data.authState; + this._show = data.authState.state === 'forgotPassword'; + this._usernameAttributes = data.usernameAttributes; + this.hide = data.hide ? data.hide : this.hide; + + this.username = + data.authState.user && data.authState.user.username + ? data.authState.user.username + : ''; + } + + @Input() hide: string[] = []; + + shouldHide(comp) { + return this.hide.filter(item => item === comp).length > 0; + } + + @Input() + set authState(authState: AuthState) { + this._authState = authState; + this._show = authState.state === 'forgotPassword'; + + this.email = + authState.user && authState.user.email ? authState.user.email : ''; + this.country_code = + authState.user && authState.user.contry_code + ? authState.user.country_code + : '1'; + this.local_phone_number = + authState.user && authState.user.local_phone_number + ? authState.user.local_phone_number + : ''; + this.username = + authState.user && authState.user.username ? authState.user.username : ''; + } + + ngOnInit() { + if (!this.amplifyService.auth()) { + throw new Error('Auth module not registered on AmplifyService provider'); + } + } + + @Input() + set usernameAttributes(usernameAttributes: string) { + this._usernameAttributes = usernameAttributes; + } + + setCode(code: string) { + this.code = code; + } + + setPassword(password: string) { + this.password = password; + } + + getforgotPwUsername() { + switch (this._usernameAttributes) { + case UsernameAttributes.EMAIL: + return this.email; + case UsernameAttributes.PHONE_NUMBER: + return composePhoneNumber(this.country_code, this.local_phone_number); + default: + return this.username; + } + } + + onSend() { + let forgotPwUsername = this.getforgotPwUsername(); + if (!forgotPwUsername) { + this.errorMessage = 'Username cannot be empty'; + return; + } + this.amplifyService + .auth() + .forgotPassword(forgotPwUsername) + .then(() => { + this.code_sent = true; + }) + .catch(err => { + this._setError(err); + this.code_sent = false; + }); + } + + onSubmit() { + this.amplifyService + .auth() + .forgotPasswordSubmit( + this.getforgotPwUsername(), + this.code, + this.password + ) + .then(() => { + const user = { username: this.username }; + this.onAlertClose(); + this.amplifyService.setAuthState({ state: 'signIn', user }); + }) + .catch(err => this._setError(err)); + } + + onSignIn() { + this.onAlertClose(); + this.amplifyService.setAuthState({ state: 'signIn', user: null }); + } + + onAlertClose() { + this._setError(null); + } + + _setError(err) { + if (!err) { + this.errorMessage = null; + return; + } + + this.errorMessage = err.message || err; + } + + getUsernameLabel() { + return ( + labelMap[this._usernameAttributes as string] || this._usernameAttributes + ); + } + + onUsernameFieldChanged(event: UsernameFieldOutput) { + this.email = event.email || this.email; + this.username = event.username || this.username; + this.country_code = event.country_code || this.country_code; + this.local_phone_number = + event.local_phone_number || this.local_phone_number; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.component.ionic.ts b/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.component.ionic.ts index 5b6c0d212c9..b24f90ea929 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.component.ionic.ts @@ -113,28 +113,29 @@ const template = ` `; @Component({ - selector: 'amplify-auth-forgot-password-ionic', - template + selector: 'amplify-auth-forgot-password-ionic', + template, }) export class ForgotPasswordComponentIonic extends ForgotPasswordComponentCore { + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + super(amplifyService); + } - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - super(amplifyService); - } + onCodeChange(val) { + this.country_code = val; + } - onCodeChange(val) { - this.country_code = val; - } + onNumberChange(val) { + this.local_phone_number = val; + } - onNumberChange(val) { - this.local_phone_number = val; - } + setUsername(username: string) { + this.username = username; + } - setUsername(username: string) { - this.username = username; - } - - setEmail(email: string) { - this.email = email; - } + setEmail(email: string) { + this.email = email; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.factory.ts b/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.factory.ts index 90c613affbf..bd92171d8b9 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.factory.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/forgot-password.factory.ts @@ -14,67 +14,66 @@ // tslint:enable import { - Component, - Input, - OnInit, - ViewChild, - ComponentFactoryResolver, - OnDestroy + Component, + Input, + OnInit, + ViewChild, + ComponentFactoryResolver, + OnDestroy, } from '@angular/core'; import { DynamicComponentDirective } from '../../../directives/dynamic.component.directive'; -import { ComponentMount } from '../../component.mount'; +import { ComponentMount } from '../../component.mount'; import { ForgotPasswordClass } from './forgot-password.class'; import { ForgotPasswordComponentIonic } from './forgot-password.component.ionic'; import { ForgotPasswordComponentCore } from './forgot-password.component.core'; import { AuthState } from '../../../providers'; @Component({ - selector: 'amplify-auth-forgot-password', - template: ` -
- -
- ` + selector: 'amplify-auth-forgot-password', + template: ` +
+ +
+ `, }) export class ForgotPasswordComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() authState: AuthState; - @Input() usernameAttributes: string = 'username'; - @Input() hide: string[] = []; - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; + @Input() framework: string; + @Input() authState: AuthState; + @Input() usernameAttributes: string = 'username'; + @Input() hide: string[] = []; + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnInit() { - this.loadComponent(); - } + ngOnInit() { + this.loadComponent(); + } - ngOnDestroy() {} + ngOnDestroy() {} - loadComponent() { + loadComponent() { + const authComponent = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(ForgotPasswordComponentIonic, { + authState: this.authState, + hide: this.hide, + usernameAttributes: this.usernameAttributes, + }) + : new ComponentMount(ForgotPasswordComponentCore, { + authState: this.authState, + hide: this.hide, + usernameAttributes: this.usernameAttributes, + }); - const authComponent = this.framework && this.framework.toLowerCase() === 'ionic' ? - new ComponentMount( - ForgotPasswordComponentIonic,{ - authState: this.authState, - hide: this.hide, - usernameAttributes: this.usernameAttributes - }) - : - new ComponentMount( - ForgotPasswordComponentCore, { - authState: this.authState, - hide: this.hide, - usernameAttributes: this.usernameAttributes - }); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + authComponent.component + ); - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(authComponent.component); + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); - - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = authComponent.data; - } + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = authComponent.data; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/index.ts b/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/index.ts index e1a923ad71e..2c80f42dea9 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/index.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/forgot-password-component/index.ts @@ -1,4 +1,3 @@ - // tslint:disable /* * Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -17,4 +16,6 @@ export { ForgotPasswordComponent } from './forgot-password.factory'; export { ForgotPasswordClass } from './forgot-password.class'; export { ForgotPasswordComponentCore } from './forgot-password.component.core'; -export { ForgotPasswordComponentIonic } from './forgot-password.component.ionic'; +export { + ForgotPasswordComponentIonic, +} from './forgot-password.component.ionic'; diff --git a/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.class.ts b/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.class.ts index fc80b23a66b..76845d7ce6f 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.class.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.class.ts @@ -14,5 +14,5 @@ // tslint:enable export class GreetingClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.component.core.ts b/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.component.core.ts index e93707ec0aa..4503fd0bdd9 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.component.core.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.component.core.ts @@ -31,60 +31,70 @@ const template = ` `; @Component({ - selector: 'amplify-auth-greetings-core', - template + selector: 'amplify-auth-greetings-core', + template, }) export class GreetingComponentCore implements OnInit { - signedIn: boolean; - greeting: string; - _usernameAttributes: string = 'username'; - protected logger: any; + signedIn: boolean; + greeting: string; + _usernameAttributes: string = 'username'; + protected logger: any; - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - this.logger = this.amplifyService.logger('GreetingComponent'); - this.subscribe(); - } + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + this.logger = this.amplifyService.logger('GreetingComponent'); + this.subscribe(); + } - @Input() - authState: AuthState; + @Input() + authState: AuthState; - @Input() - set usernameAttributes(usernameAttributes: string) { - this._usernameAttributes = usernameAttributes; - } - - ngOnInit() { - if (!this.amplifyService.auth()){ - throw new Error('Auth module not registered on AmplifyService provider'); - } - } + @Input() + set usernameAttributes(usernameAttributes: string) { + this._usernameAttributes = usernameAttributes; + } - subscribe() { - this.amplifyService.authStateChange$ - .subscribe(state => this.setAuthState(state)); - } + ngOnInit() { + if (!this.amplifyService.auth()) { + throw new Error('Auth module not registered on AmplifyService provider'); + } + } - setAuthState(authState: AuthState) { - this.authState = authState; - this.signedIn = authState.state === 'signedIn'; + subscribe() { + this.amplifyService.authStateChange$.subscribe(state => + this.setAuthState(state) + ); + } - let username = ""; - if (authState.user) { - if (this._usernameAttributes === UsernameAttributes.EMAIL) { - username = authState.user.attributes? authState.user.attributes.email : authState.user.username; - } else if (this._usernameAttributes === UsernameAttributes.PHONE_NUMBER) { - username = authState.user.attributes? authState.user.attributes.phone_number : authState.user.username; - } else { - username = authState.user.username; - } - } - - this.greeting = this.signedIn - ? this.amplifyService.i18n().get("Hello, {{username}}").replace('{{username}}', username) - : ""; - } + setAuthState(authState: AuthState) { + this.authState = authState; + this.signedIn = authState.state === 'signedIn'; - onSignOut() { - this.amplifyService.auth().signOut(); - } + let username = ''; + if (authState.user) { + if (this._usernameAttributes === UsernameAttributes.EMAIL) { + username = authState.user.attributes + ? authState.user.attributes.email + : authState.user.username; + } else if (this._usernameAttributes === UsernameAttributes.PHONE_NUMBER) { + username = authState.user.attributes + ? authState.user.attributes.phone_number + : authState.user.username; + } else { + username = authState.user.username; + } + } + + this.greeting = this.signedIn + ? this.amplifyService + .i18n() + .get('Hello, {{username}}') + .replace('{{username}}', username) + : ''; + } + + onSignOut() { + this.amplifyService.auth().signOut(); + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.component.ionic.ts b/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.component.ionic.ts index 1f8b772f661..2bbb3c87ab9 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.component.ionic.ts @@ -34,12 +34,13 @@ const template = ` `; @Component({ - selector: 'amplify-auth-greetings-ionic', - template + selector: 'amplify-auth-greetings-ionic', + template, }) export class GreetingComponentIonic extends GreetingComponentCore { - - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - super(amplifyService); - } + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + super(amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.factory.ts b/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.factory.ts index 112123cd67d..146cd32063f 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.factory.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/greeting-component/greeting.factory.ts @@ -14,56 +14,64 @@ // tslint:enable import { - Component, - Input, - OnInit, - ViewChild, - ComponentFactoryResolver, - OnDestroy } -from '@angular/core'; + Component, + Input, + OnInit, + ViewChild, + ComponentFactoryResolver, + OnDestroy, +} from '@angular/core'; import { DynamicComponentDirective } from '../../../directives/dynamic.component.directive'; -import { ComponentMount } from '../../component.mount'; +import { ComponentMount } from '../../component.mount'; import { GreetingClass } from './greeting.class'; import { GreetingComponentIonic } from './greeting.component.ionic'; import { GreetingComponentCore } from './greeting.component.core'; import { AuthState } from '../../../providers'; @Component({ - selector: 'amplify-auth-greetings', - template: ` -
- -
- ` + selector: 'amplify-auth-greetings', + template: ` +
+ +
+ `, }) export class GreetingComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() authState: AuthState; - @Input() usernameAttributes: string = 'username'; - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; + @Input() framework: string; + @Input() authState: AuthState; + @Input() usernameAttributes: string = 'username'; + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnInit() { - this.loadComponent(); - } + ngOnInit() { + this.loadComponent(); + } - ngOnDestroy() {} + ngOnDestroy() {} - loadComponent() { + loadComponent() { + let authComponent = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(GreetingComponentIonic, { + authState: this.authState, + usernameAttributes: this.usernameAttributes, + }) + : new ComponentMount(GreetingComponentCore, { + authState: this.authState, + usernameAttributes: this.usernameAttributes, + }); - let authComponent = this.framework && this.framework.toLowerCase() === 'ionic' ? - new ComponentMount(GreetingComponentIonic,{authState: this.authState, usernameAttributes: this.usernameAttributes}) : - new ComponentMount(GreetingComponentCore, {authState: this.authState, usernameAttributes: this.usernameAttributes}); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + authComponent.component + ); - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(authComponent.component); + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); - - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = authComponent.data; - } + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = authComponent.data; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/phone-field-component/phone-field.component.core.ts b/packages/aws-amplify-angular/src/components/authenticator/phone-field-component/phone-field.component.core.ts index 1d82c6a5520..806dd0eac03 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/phone-field-component/phone-field.component.core.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/phone-field-component/phone-field.component.core.ts @@ -13,10 +13,17 @@ */ // tslint:enable -import { Component, Input, OnInit, EventEmitter, Inject, Output } from '@angular/core'; +import { + Component, + Input, + OnInit, + EventEmitter, + Inject, + Output, +} from '@angular/core'; import { AmplifyService } from '../../../providers/amplify.service'; import { PhoneFieldOutput } from '../types'; -import { countrylist, country } from '../../../assets/countries'; +import { countrylist, country } from '../../../assets/countries'; import { auth } from '../../../assets/data-test-attributes'; const template = ` @@ -57,73 +64,78 @@ const template = ` `; @Component({ - selector: 'amplify-auth-phone-field-core', - template, + selector: 'amplify-auth-phone-field-core', + template, }) export class PhoneFieldComponentCore implements OnInit { - _placeholder : string = ''; - _label: string = 'Phone Number'; - _required: boolean = true; - _country_code: string = '1'; - _local_phone_number: string = ''; - _countries: country[]; + _placeholder: string = ''; + _label: string = 'Phone Number'; + _required: boolean = true; + _country_code: string = '1'; + _local_phone_number: string = ''; + _countries: country[]; - constructor(@Inject(AmplifyService) public amplifyService: AmplifyService) { - this._countries = countrylist; - } + constructor(@Inject(AmplifyService) public amplifyService: AmplifyService) { + this._countries = countrylist; + } - @Input() - set data(data: any) { - this._placeholder = data.placeholder || this._placeholder; - this._label = data.label || this._label; - this._country_code = data.defaultCountryCode || this._country_code; - this._required = data.required === undefined? this._required : data.required; - } + @Input() + set data(data: any) { + this._placeholder = data.placeholder || this._placeholder; + this._label = data.label || this._label; + this._country_code = data.defaultCountryCode || this._country_code; + this._required = + data.required === undefined ? this._required : data.required; + } - @Input() - set placeholder(placeholder: string) { - this._placeholder = placeholder; - } + @Input() + set placeholder(placeholder: string) { + this._placeholder = placeholder; + } - @Input() - set label(label: string) { - this._label = label; - } + @Input() + set label(label: string) { + this._label = label; + } - @Input() - set required(required: boolean) { - this._required = required; - } + @Input() + set required(required: boolean) { + this._required = required; + } - @Input() - set defaultCountryCode(defaultCountryCode: string) { - this._country_code = defaultCountryCode; - } + @Input() + set defaultCountryCode(defaultCountryCode: string) { + this._country_code = defaultCountryCode; + } - @Output() - phoneFieldChanged: EventEmitter = new EventEmitter(); + @Output() + phoneFieldChanged: EventEmitter = new EventEmitter< + PhoneFieldOutput + >(); - ngOnInit() {} + ngOnInit() {} - ngOnDestroy() {} + ngOnDestroy() {} - setCountryCode(country_code: string) { - this._country_code = country_code; - this.phoneFieldChanged.emit({ - country_code: this._country_code, - local_phone_number: this._local_phone_number - }); - } + setCountryCode(country_code: string) { + this._country_code = country_code; + this.phoneFieldChanged.emit({ + country_code: this._country_code, + local_phone_number: this._local_phone_number, + }); + } - setLocalPhoneNumber(local_phone_number: string) { - this._local_phone_number = local_phone_number; - this.phoneFieldChanged.emit({ - country_code: this._country_code, - local_phone_number: this._local_phone_number - }); - } + setLocalPhoneNumber(local_phone_number: string) { + this._local_phone_number = local_phone_number; + this.phoneFieldChanged.emit({ + country_code: this._country_code, + local_phone_number: this._local_phone_number, + }); + } - getPlaceholder() { - return this.amplifyService.i18n().get(`Enter your phone number` || this._placeholder); - } + getPlaceholder() { + return this.amplifyService + .i18n() + .get(`Enter your phone number` || this._placeholder); + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/phone-field-component/phone-field.component.ionic.ts b/packages/aws-amplify-angular/src/components/authenticator/phone-field-component/phone-field.component.ionic.ts index 7fbed0aac2a..776c9b526f6 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/phone-field-component/phone-field.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/phone-field-component/phone-field.component.ionic.ts @@ -57,12 +57,11 @@ const template = ` `; @Component({ - selector: 'amplify-auth-phone-field-ionic', - template, + selector: 'amplify-auth-phone-field-ionic', + template, }) export class PhoneFieldComponentIonic extends PhoneFieldComponentCore { - - constructor(@Inject(AmplifyService) public amplifyService: AmplifyService) { - super(amplifyService); - } + constructor(@Inject(AmplifyService) public amplifyService: AmplifyService) { + super(amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/index.ts b/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/index.ts index 60391378ec0..8acdbb2de97 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/index.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/index.ts @@ -1,4 +1,3 @@ - // tslint:disable /* * Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -16,5 +15,9 @@ export { RequireNewPasswordComponent } from './require-new-password.factory'; export { RequireNewPasswordClass } from './require-new-password.class'; -export { RequireNewPasswordComponentCore } from './require-new-password.component.core'; -export { RequireNewPasswordComponentIonic } from './require-new-password.component.ionic'; +export { + RequireNewPasswordComponentCore, +} from './require-new-password.component.core'; +export { + RequireNewPasswordComponentIonic, +} from './require-new-password.component.ionic'; diff --git a/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.class.ts b/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.class.ts index cab917f7616..5798ebe1687 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.class.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.class.ts @@ -13,7 +13,6 @@ */ // tslint:enable - export class RequireNewPasswordClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.component.core.ts b/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.component.core.ts index d6d71bf0043..7734e094414 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.component.core.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.component.core.ts @@ -65,81 +65,79 @@ const template = ` `; @Component({ - selector: 'amplify-auth-require-new-password-core', - template + selector: 'amplify-auth-require-new-password-core', + template, }) export class RequireNewPasswordComponentCore implements OnInit { - _authState: AuthState; - _show: boolean; - password: string; - errorMessage: string; - protected logger: any; + _authState: AuthState; + _show: boolean; + password: string; + errorMessage: string; + protected logger: any; - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - this.logger = this.amplifyService.logger('RequireNewPasswordComponent'); - } + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + this.logger = this.amplifyService.logger('RequireNewPasswordComponent'); + } - @Input() - set authState(authState: AuthState) { - this._authState = authState; - this._show = authState.state === 'requireNewPassword'; - } + @Input() + set authState(authState: AuthState) { + this._authState = authState; + this._show = authState.state === 'requireNewPassword'; + } - @Input() hide: string[] = []; + @Input() hide: string[] = []; - @Input() - set data(data: any) { - this._authState = data.authState; - this._show = data.authState.state === 'requireNewPassword'; - this.hide = data.hide ? data.hide : this.hide; - } + @Input() + set data(data: any) { + this._authState = data.authState; + this._show = data.authState.state === 'requireNewPassword'; + this.hide = data.hide ? data.hide : this.hide; + } - ngOnInit() { - if (!this.amplifyService.auth()){ - throw new Error('Auth module not registered on AmplifyService provider'); - } - } + ngOnInit() { + if (!this.amplifyService.auth()) { + throw new Error('Auth module not registered on AmplifyService provider'); + } + } - shouldHide(comp) { - return this.hide.filter(item => item === comp) - .length > 0; - } + shouldHide(comp) { + return this.hide.filter(item => item === comp).length > 0; + } - setPassword(password: string) { - this.password = password; - } + setPassword(password: string) { + this.password = password; + } - onSubmit() { - const { user } = this._authState; - const { requiredAttributes } = user.challengeParam; - this.amplifyService.auth() - .completeNewPassword( - user, - this.password, - requiredAttributes - ) - .then(() => { - this.onAlertClose(); - this.amplifyService.setAuthState({ state: 'signIn', user }); - }) - .catch(err => this._setError(err)); - } + onSubmit() { + const { user } = this._authState; + const { requiredAttributes } = user.challengeParam; + this.amplifyService + .auth() + .completeNewPassword(user, this.password, requiredAttributes) + .then(() => { + this.onAlertClose(); + this.amplifyService.setAuthState({ state: 'signIn', user }); + }) + .catch(err => this._setError(err)); + } - onSignIn() { - this.onAlertClose(); - this.amplifyService.setAuthState({ state: 'signIn', user: null }); - } + onSignIn() { + this.onAlertClose(); + this.amplifyService.setAuthState({ state: 'signIn', user: null }); + } - onAlertClose() { - this._setError(null); - } + onAlertClose() { + this._setError(null); + } - _setError(err) { - if (!err) { - this.errorMessage = null; - return; - } + _setError(err) { + if (!err) { + this.errorMessage = null; + return; + } - this.errorMessage = err.message || err; - } + this.errorMessage = err.message || err; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.component.ionic.ts b/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.component.ionic.ts index f0c53367ce9..969264cecbb 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.component.ionic.ts @@ -77,12 +77,13 @@ const template = ` `; @Component({ - selector: 'amplify-auth-require-new-password-ionic', - template + selector: 'amplify-auth-require-new-password-ionic', + template, }) export class RequireNewPasswordComponentIonic extends RequireNewPasswordComponentCore { - - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - super(amplifyService); - } + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + super(amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.factory.ts b/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.factory.ts index 7f426882181..fb1cec7f7bb 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.factory.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/require-new-password-component/require-new-password.factory.ts @@ -14,61 +14,64 @@ // tslint:enable import { - Component, - Input, - OnInit, - ViewChild, - ComponentFactoryResolver, - OnDestroy + Component, + Input, + OnInit, + ViewChild, + ComponentFactoryResolver, + OnDestroy, } from '@angular/core'; import { DynamicComponentDirective } from '../../../directives/dynamic.component.directive'; -import { ComponentMount } from '../../component.mount'; +import { ComponentMount } from '../../component.mount'; import { RequireNewPasswordClass } from './require-new-password.class'; import { RequireNewPasswordComponentIonic } from './require-new-password.component.ionic'; import { RequireNewPasswordComponentCore } from './require-new-password.component.core'; import { AuthState } from '../../../providers'; @Component({ - selector: 'amplify-auth-require-new-password', - template: ` -
- -
- ` + selector: 'amplify-auth-require-new-password', + template: ` +
+ +
+ `, }) export class RequireNewPasswordComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() authState: AuthState; - @Input() hide: string[] = []; - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; + @Input() framework: string; + @Input() authState: AuthState; + @Input() hide: string[] = []; + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnInit() { - this.loadComponent(); - } + ngOnInit() { + this.loadComponent(); + } - ngOnDestroy() {} + ngOnDestroy() {} - loadComponent() { + loadComponent() { + const requireNewPasswordComponent = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(RequireNewPasswordComponentIonic, { + authState: this.authState, + hide: this.hide, + }) + : new ComponentMount(RequireNewPasswordComponentCore, { + authState: this.authState, + hide: this.hide, + }); - const requireNewPasswordComponent = this.framework && this.framework.toLowerCase() === 'ionic' ? - new ComponentMount(RequireNewPasswordComponentIonic,{ - authState: this.authState, - hide: this.hide - }) : - new ComponentMount(RequireNewPasswordComponentCore, { - authState: this.authState, - hide: this.hide - }); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + requireNewPasswordComponent.component + ); - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(requireNewPasswordComponent.component); + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); - - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = requireNewPasswordComponent.data; - } + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = + requireNewPasswordComponent.data; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/index.ts b/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/index.ts index d6132236ccb..a5eddbd1933 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/index.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/index.ts @@ -13,7 +13,6 @@ */ // tslint:enable - export { SignInComponent } from './sign-in.component.factory'; export { SignInClass } from './sign-in.class'; export { SignInComponentCore } from './sign-in.component.core'; diff --git a/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.class.ts b/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.class.ts index 7e984bafaca..8d19183f7fa 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.class.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.class.ts @@ -14,5 +14,5 @@ // tslint:enable export class SignInClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.core.ts b/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.core.ts index aa87c31b948..3fe15d6a921 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.core.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.core.ts @@ -89,147 +89,162 @@ const template = ` `; @Component({ - selector: 'amplify-auth-sign-in-core', - template + selector: 'amplify-auth-sign-in-core', + template, }) export class SignInComponentCore implements OnInit { - _authState: AuthState; - _show: boolean; - _usernameAttributes: string = 'username'; - username: string; - password: string; - errorMessage: string; - local_phone_number: string = ''; - country_code: string = '1'; - email: string = ''; - - signInUsername = ''; - protected logger: any; - - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - this.logger = this.amplifyService.logger('SignInComponent'); - this.onUsernameFieldChanged = this.onUsernameFieldChanged.bind(this); - } - - @Input() - set data(data: any) { - this.hide = data.hide ? data.hide : this.hide; - this._usernameAttributes = data.usernameAttributes; - } - - @Input() hide: string[] = []; - - @Input() - set authState(authState: AuthState) { - this._authState = authState; - this._show = includes(['signIn', 'signedOut', 'signedUp'], authState.state); - this.username = authState.user? authState.user.username || '' : ''; - this.email = authState.user? authState.user.email || '' : ''; - this.country_code = authState.user && - authState.user.country_code ? - authState.user.country_code : - this.country_code; - this.local_phone_number = authState.user? authState.user.local_phone_number || '' : ''; - } - - @Input() - set usernameAttributes(usernameAttributes: string) { - this._usernameAttributes = usernameAttributes; - } - - ngOnInit() { - if (!this.amplifyService.auth()){ - throw new Error('Auth module not registered on AmplifyService provider'); - } - } - - shouldHide(comp) { - return this.hide.filter(item => item === comp) - .length > 0; - } - - setUsername(username: string) { - this.username = username; - } - - setPassword(password: string) { - this.password = password; - } - - onSignIn() { - this.amplifyService.auth().signIn(this.getSignInUsername(), this.password) - .then(user => { - if (user['challengeName'] === 'SMS_MFA' || user['challengeName'] === 'SOFTWARE_TOKEN_MFA') { - this.amplifyService.setAuthState({ state: 'confirmSignIn', user }); - } else if (user['challengeName'] === 'NEW_PASSWORD_REQUIRED') { - this.amplifyService.setAuthState({ state: 'requireNewPassword', user }); - } else if ( - user['challengeName'] === 'CUSTOM_CHALLENGE' && - user.challengeParam && - user.challengeParam.trigger === 'true' - ) { - this.amplifyService.setAuthState({ state: 'customConfirmSignIn', user }); - } - }) - .catch((err) => { - this._setError(err); - }); - } - - onAlertClose() { - this._setError(null); - } - - getUserObj() { - const user = this.username || this.email || this.local_phone_number? - { - username: this.username, - email: this.email, - local_phone_number: this.local_phone_number, - courtry_code: this.country_code - } - : - null; - - return user; - } - - onForgotPassword() { - const user = this.getUserObj(); - this.onAlertClose(); - this.amplifyService.setAuthState({ state: 'forgotPassword', user }); - } - - onSignUp() { - const user = this.getUserObj(); - this.onAlertClose(); - this.amplifyService.setAuthState({ state: 'signUp', user }); - } - - _setError(err) { - if (!err) { - this.errorMessage = null; - return; - } - this.errorMessage = err.message || err; - this.logger.error(this.errorMessage); - } - - onUsernameFieldChanged(event: UsernameFieldOutput) { - this.email = event.email || this.email; - this.username = event.username || this.username; - this.country_code = event.country_code || this.country_code; - this.local_phone_number = event.local_phone_number || this.local_phone_number; - } - - getSignInUsername() { - switch(this._usernameAttributes) { - case UsernameAttributes.EMAIL: - return this.email; - case UsernameAttributes.PHONE_NUMBER: - return composePhoneNumber(this.country_code, this.local_phone_number); - default: - return this.username; - } - } + _authState: AuthState; + _show: boolean; + _usernameAttributes: string = 'username'; + username: string; + password: string; + errorMessage: string; + local_phone_number: string = ''; + country_code: string = '1'; + email: string = ''; + + signInUsername = ''; + protected logger: any; + + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + this.logger = this.amplifyService.logger('SignInComponent'); + this.onUsernameFieldChanged = this.onUsernameFieldChanged.bind(this); + } + + @Input() + set data(data: any) { + this.hide = data.hide ? data.hide : this.hide; + this._usernameAttributes = data.usernameAttributes; + } + + @Input() hide: string[] = []; + + @Input() + set authState(authState: AuthState) { + this._authState = authState; + this._show = includes(['signIn', 'signedOut', 'signedUp'], authState.state); + this.username = authState.user ? authState.user.username || '' : ''; + this.email = authState.user ? authState.user.email || '' : ''; + this.country_code = + authState.user && authState.user.country_code + ? authState.user.country_code + : this.country_code; + this.local_phone_number = authState.user + ? authState.user.local_phone_number || '' + : ''; + } + + @Input() + set usernameAttributes(usernameAttributes: string) { + this._usernameAttributes = usernameAttributes; + } + + ngOnInit() { + if (!this.amplifyService.auth()) { + throw new Error('Auth module not registered on AmplifyService provider'); + } + } + + shouldHide(comp) { + return this.hide.filter(item => item === comp).length > 0; + } + + setUsername(username: string) { + this.username = username; + } + + setPassword(password: string) { + this.password = password; + } + + onSignIn() { + this.amplifyService + .auth() + .signIn(this.getSignInUsername(), this.password) + .then(user => { + if ( + user['challengeName'] === 'SMS_MFA' || + user['challengeName'] === 'SOFTWARE_TOKEN_MFA' + ) { + this.amplifyService.setAuthState({ state: 'confirmSignIn', user }); + } else if (user['challengeName'] === 'NEW_PASSWORD_REQUIRED') { + this.amplifyService.setAuthState({ + state: 'requireNewPassword', + user, + }); + } else if ( + user['challengeName'] === 'CUSTOM_CHALLENGE' && + user.challengeParam && + user.challengeParam.trigger === 'true' + ) { + this.amplifyService.setAuthState({ + state: 'customConfirmSignIn', + user, + }); + } + }) + .catch(err => { + this._setError(err); + }); + } + + onAlertClose() { + this._setError(null); + } + + getUserObj() { + const user = + this.username || this.email || this.local_phone_number + ? { + username: this.username, + email: this.email, + local_phone_number: this.local_phone_number, + courtry_code: this.country_code, + } + : null; + + return user; + } + + onForgotPassword() { + const user = this.getUserObj(); + this.onAlertClose(); + this.amplifyService.setAuthState({ state: 'forgotPassword', user }); + } + + onSignUp() { + const user = this.getUserObj(); + this.onAlertClose(); + this.amplifyService.setAuthState({ state: 'signUp', user }); + } + + _setError(err) { + if (!err) { + this.errorMessage = null; + return; + } + this.errorMessage = err.message || err; + this.logger.error(this.errorMessage); + } + + onUsernameFieldChanged(event: UsernameFieldOutput) { + this.email = event.email || this.email; + this.username = event.username || this.username; + this.country_code = event.country_code || this.country_code; + this.local_phone_number = + event.local_phone_number || this.local_phone_number; + } + + getSignInUsername() { + switch (this._usernameAttributes) { + case UsernameAttributes.EMAIL: + return this.email; + case UsernameAttributes.PHONE_NUMBER: + return composePhoneNumber(this.country_code, this.local_phone_number); + default: + return this.username; + } + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.factory.ts b/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.factory.ts index e6bf757da39..fd539aee42f 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.factory.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.factory.ts @@ -14,15 +14,15 @@ // tslint:enable import { - Component, - Input, - OnInit, - ViewChild, - ComponentFactoryResolver, - OnDestroy + Component, + Input, + OnInit, + ViewChild, + ComponentFactoryResolver, + OnDestroy, } from '@angular/core'; import { DynamicComponentDirective } from '../../../directives/dynamic.component.directive'; -import { ComponentMount } from '../../component.mount'; +import { ComponentMount } from '../../component.mount'; import { SignInClass } from './sign-in.class'; import { SignInComponentIonic } from './sign-in.component.ionic'; import { SignInComponentCore } from './sign-in.component.core'; @@ -30,52 +30,51 @@ import { AuthState } from '../../../providers'; import { authDecorator } from '../../../providers/auth.decorator'; @Component({ - selector: 'amplify-auth-sign-in', - template: ` -
- -
- ` + selector: 'amplify-auth-sign-in', + template: ` +
+ +
+ `, }) export class SignInComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() authState: AuthState; - @Input() usernameAttributes: string = 'username'; - @Input() hide: string[] = []; - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; + @Input() framework: string; + @Input() authState: AuthState; + @Input() usernameAttributes: string = 'username'; + @Input() hide: string[] = []; + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnInit() { - this.loadComponent(); - } + ngOnInit() { + this.loadComponent(); + } - ngOnDestroy() {} + ngOnDestroy() {} - loadComponent() { + loadComponent() { + let authComponent = + this.framework && this.framework === 'ionic' + ? new ComponentMount(SignInComponentIonic, { + authState: this.authState, + hide: this.hide, + usernameAttributes: this.usernameAttributes, + }) + : new ComponentMount(SignInComponentCore, { + authState: this.authState, + hide: this.hide, + usernameAttributes: this.usernameAttributes, + }); - let authComponent = this.framework && this.framework === 'ionic' ? - new ComponentMount( - SignInComponentIonic,{ - authState: this.authState, - hide: this.hide, - usernameAttributes: this.usernameAttributes - }) - : - new ComponentMount( - SignInComponentCore, { - authState: this.authState, - hide: this.hide, - usernameAttributes: this.usernameAttributes - }); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + authComponent.component + ); - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(authComponent.component); + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); - - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = authComponent.data; - } + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = authComponent.data; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.ionic.ts b/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.ionic.ts index 3e94f8c0b43..f4e083bcc5f 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/sign-in-component/sign-in.component.ionic.ts @@ -88,12 +88,13 @@ const template = ` `; @Component({ - selector: 'amplify-auth-sign-in-ionic', - template + selector: 'amplify-auth-sign-in-ionic', + template, }) export class SignInComponentIonic extends SignInComponentCore { - - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - super(amplifyService); - } + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + super(amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.class.ts b/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.class.ts index 0e531be7279..f99ccf87a73 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.class.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.class.ts @@ -13,5 +13,5 @@ */ // tslint:enable export class SignUpClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.component.core.ts b/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.component.core.ts index 4b7d8680958..a4494450dfa 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.component.core.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.component.core.ts @@ -14,7 +14,10 @@ // tslint:enable import { Component, Input, OnInit, Inject } from '@angular/core'; -import defaultSignUpFieldAssets, { signUpWithEmailFields, signUpWithPhoneNumberFields } from '../../../assets/default-sign-up-fields'; +import defaultSignUpFieldAssets, { + signUpWithEmailFields, + signUpWithPhoneNumberFields, +} from '../../../assets/default-sign-up-fields'; import { UsernameAttributes, PhoneFieldOutput } from '../types'; import { AmplifyService } from '../../../providers/amplify.service'; import { AuthState } from '../../../providers/auth.state'; @@ -86,322 +89,337 @@ const template = ` `; -export class SignUpField{ - label: string; - key: string; - required?: boolean; - type?: string; - displayOrder?:number; - invalid?: boolean; - custom?: boolean; - signUpWith?: boolean; +export class SignUpField { + label: string; + key: string; + required?: boolean; + type?: string; + displayOrder?: number; + invalid?: boolean; + custom?: boolean; + signUpWith?: boolean; } @Component({ - selector: 'amplify-auth-sign-up-core', - template, + selector: 'amplify-auth-sign-up-core', + template, }) - export class SignUpComponentCore implements OnInit { - _authState: AuthState; - _show: boolean; - _signUpConfig: any; - _usernameAttributes: string = 'username'; - user: any = {}; - local_phone_number: string; - country_code: string = '1'; - header: string = 'Create a new account'; - defaultSignUpFields: SignUpField[] = defaultSignUpFieldAssets; - signUpFields: SignUpField[] = this.defaultSignUpFields; - errorMessage: string; - hiddenFields: any = []; - passwordPolicy: string; - defaultCountryCode: string; - protected logger: any; - - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - this.logger = this.amplifyService.logger('SignUpComponent'); - } - - @Input() - set data(data: any) { - this._authState = data.authState; - this._show = data.authState.state === 'signUp'; - this._usernameAttributes = data.usernameAttributes; - if (data.signUpConfig) { - this._signUpConfig = data.signUpConfig; - if (this._signUpConfig.defaultCountryCode) { - this.country_code = this._signUpConfig.defaultCountryCode; - } - if (this._signUpConfig.signUpFields) { - this.signUpFields = this._signUpConfig.signUpFields; - } - if (this._signUpConfig.header) { - this.header = this._signUpConfig.header; - } - if (this._signUpConfig.hiddenDefaults) { - this.hiddenFields = this._signUpConfig.hiddenDefaults; - } - - if (this._usernameAttributes === UsernameAttributes.EMAIL) { - this.signUpFields = signUpWithEmailFields; - this.defaultSignUpFields = signUpWithEmailFields; - } else if (this._usernameAttributes === UsernameAttributes.PHONE_NUMBER) { - this.signUpFields = signUpWithPhoneNumberFields; - this.defaultSignUpFields = signUpWithPhoneNumberFields; - } - - if (this._signUpConfig.passwordPolicy) { - this.passwordPolicy = this._signUpConfig.passwordPolicy; - } - } - } - - @Input() hide: string[] = []; - - @Input() - set usernameAttributes(usernameAttributes: string) { - this._usernameAttributes = usernameAttributes; - if (this._usernameAttributes === UsernameAttributes.EMAIL) { - this.signUpFields = signUpWithEmailFields; - this.defaultSignUpFields = signUpWithEmailFields; - } else if (this._usernameAttributes === UsernameAttributes.PHONE_NUMBER) { - this.signUpFields = signUpWithPhoneNumberFields; - this.defaultSignUpFields = signUpWithPhoneNumberFields; - } - } - - @Input() - set authState(authState: AuthState) { - this._authState = authState; - this._show = authState.state === 'signUp'; - } - - @Input() - set signUpConfig(signUpConfig: any) { - if (signUpConfig) { - this._signUpConfig = signUpConfig; - if (this._signUpConfig.defaultCountryCode) { - this.country_code = this._signUpConfig.defaultCountryCode; - } - if (this._signUpConfig.signUpFields) { - this.signUpFields = this._signUpConfig.signUpFields; - } - if (this._signUpConfig.header) { - this.header = this._signUpConfig.header; - } - if (this._signUpConfig.hiddenDefaults) { - this.hiddenFields = this._signUpConfig.hiddenDefaults; - } - if (this._signUpConfig.passwordPolicy) { - this.passwordPolicy = this._signUpConfig.passwordPolicy; - } - } - } - - ngOnInit() { - if (!this.amplifyService.auth()){ - this.logger.warn('Auth module not registered on AmplifyService provider'); - } - this.sortFields(); - } - - - shouldHide(comp) { - return this.hide.filter(item => item === comp) - .length > 0; - } - - onSignUp() { - - // validate required inputs - const validation = this.validate(); - if (validation && validation.length > 0) { - return this._setError(`The following fields need to be filled out: ${validation.join(', ')}`); - } - - // create user attribute property - this.user.attributes = {}; - - // format phone number if it is a signUpField - const phoneNumberRequested = this.signUpFields.find((el) => { - return el.key === 'phone_number'; - }); - if (phoneNumberRequested) { - this.user.phone_number = composePhoneNumber(this.country_code, this.local_phone_number); - } - - // create user key and value arrays - const userKeys = Object.keys(this.user); - const userValues = userKeys.map(key => this.user[key]); - - // format data for Cognito user pool - userKeys.forEach((key, index) => { - if (key !== 'username' && key !== 'password' && key !== 'attributes') { - // needsPrefix determines if a custom attribute is indicated - // and prepends 'custom:' to the key before sending to Cognito if needed - const newKey = `${this.needPrefix(key) ? 'custom:' : ''}${key}`; - this.user.attributes[newKey] = userValues[index]; - } - }); - - - let labelCheck = false; - this.signUpFields.forEach(field => { - if (field.label === this.getUsernameLabel()) { - this.amplifyService.logger(`Changing the username to the value of ${field.label}`, 'DEBUG'); - this.user.username = this.user.attributes[field.key] || this.user.username; - labelCheck = true; - } - }); - if (!labelCheck && !this.user.username) { - // if the customer customized the username field in the sign up form - // He needs to either set the key of that field to 'username' - // Or make the label of the field the same as the 'usernameAttributes' - throw new Error(`Couldn't find the label: ${this.getUsernameLabel()}, in sign up fields according to usernameAttributes!`); - } - - this.amplifyService.auth() - .signUp(this.user) - .then((user) => { - const username = this.user.username; - this.user = {}; - this.onAlertClose(); - this.amplifyService - .setAuthState({ state: 'confirmSignUp', user: { 'username': username} }); - }) - .catch(err => this._setError(err)); - } - - onSignIn() { - this.onAlertClose(); - this.amplifyService.setAuthState({ state: 'signIn', user: null }); - } - - needPrefix(key) { - const field = this.signUpFields.find(e => e.key === key); - if (key.indexOf('custom:') !== 0) { - return field.custom ; - } else if (key.indexOf('custom:') === 0 && field.custom === false) { - this.logger.warn('Custom prefix prepended to key but custom field flag is set to false'); - } - return null; - } - - onConfirmSignUp() { - this.onAlertClose(); - this.amplifyService - .setAuthState({ state: 'confirmSignUp', user: { 'username': this.user.username } }); - } - - sortFields() { - - if (this.hiddenFields.length > 0){ - this.defaultSignUpFields = this.defaultSignUpFields.filter((d) => { - return !this.hiddenFields.includes(d.key); - }); - } - - if (this._signUpConfig && - this._signUpConfig.signUpFields && - this._signUpConfig.signUpFields.length > 0 - ) { - - if (!this._signUpConfig.hideAllDefaults) { - // see if fields passed to component should override defaults - this.defaultSignUpFields.forEach((f, i) => { - const matchKey = this.signUpFields.findIndex((d) => { - return d.key === f.key; - }); - if (matchKey === -1) { - this.signUpFields.push(f); - } - }); - } - - /* + _authState: AuthState; + _show: boolean; + _signUpConfig: any; + _usernameAttributes: string = 'username'; + user: any = {}; + local_phone_number: string; + country_code: string = '1'; + header: string = 'Create a new account'; + defaultSignUpFields: SignUpField[] = defaultSignUpFieldAssets; + signUpFields: SignUpField[] = this.defaultSignUpFields; + errorMessage: string; + hiddenFields: any = []; + passwordPolicy: string; + defaultCountryCode: string; + protected logger: any; + + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + this.logger = this.amplifyService.logger('SignUpComponent'); + } + + @Input() + set data(data: any) { + this._authState = data.authState; + this._show = data.authState.state === 'signUp'; + this._usernameAttributes = data.usernameAttributes; + if (data.signUpConfig) { + this._signUpConfig = data.signUpConfig; + if (this._signUpConfig.defaultCountryCode) { + this.country_code = this._signUpConfig.defaultCountryCode; + } + if (this._signUpConfig.signUpFields) { + this.signUpFields = this._signUpConfig.signUpFields; + } + if (this._signUpConfig.header) { + this.header = this._signUpConfig.header; + } + if (this._signUpConfig.hiddenDefaults) { + this.hiddenFields = this._signUpConfig.hiddenDefaults; + } + + if (this._usernameAttributes === UsernameAttributes.EMAIL) { + this.signUpFields = signUpWithEmailFields; + this.defaultSignUpFields = signUpWithEmailFields; + } else if (this._usernameAttributes === UsernameAttributes.PHONE_NUMBER) { + this.signUpFields = signUpWithPhoneNumberFields; + this.defaultSignUpFields = signUpWithPhoneNumberFields; + } + + if (this._signUpConfig.passwordPolicy) { + this.passwordPolicy = this._signUpConfig.passwordPolicy; + } + } + } + + @Input() hide: string[] = []; + + @Input() + set usernameAttributes(usernameAttributes: string) { + this._usernameAttributes = usernameAttributes; + if (this._usernameAttributes === UsernameAttributes.EMAIL) { + this.signUpFields = signUpWithEmailFields; + this.defaultSignUpFields = signUpWithEmailFields; + } else if (this._usernameAttributes === UsernameAttributes.PHONE_NUMBER) { + this.signUpFields = signUpWithPhoneNumberFields; + this.defaultSignUpFields = signUpWithPhoneNumberFields; + } + } + + @Input() + set authState(authState: AuthState) { + this._authState = authState; + this._show = authState.state === 'signUp'; + } + + @Input() + set signUpConfig(signUpConfig: any) { + if (signUpConfig) { + this._signUpConfig = signUpConfig; + if (this._signUpConfig.defaultCountryCode) { + this.country_code = this._signUpConfig.defaultCountryCode; + } + if (this._signUpConfig.signUpFields) { + this.signUpFields = this._signUpConfig.signUpFields; + } + if (this._signUpConfig.header) { + this.header = this._signUpConfig.header; + } + if (this._signUpConfig.hiddenDefaults) { + this.hiddenFields = this._signUpConfig.hiddenDefaults; + } + if (this._signUpConfig.passwordPolicy) { + this.passwordPolicy = this._signUpConfig.passwordPolicy; + } + } + } + + ngOnInit() { + if (!this.amplifyService.auth()) { + this.logger.warn('Auth module not registered on AmplifyService provider'); + } + this.sortFields(); + } + + shouldHide(comp) { + return this.hide.filter(item => item === comp).length > 0; + } + + onSignUp() { + // validate required inputs + const validation = this.validate(); + if (validation && validation.length > 0) { + return this._setError( + `The following fields need to be filled out: ${validation.join(', ')}` + ); + } + + // create user attribute property + this.user.attributes = {}; + + // format phone number if it is a signUpField + const phoneNumberRequested = this.signUpFields.find(el => { + return el.key === 'phone_number'; + }); + if (phoneNumberRequested) { + this.user.phone_number = composePhoneNumber( + this.country_code, + this.local_phone_number + ); + } + + // create user key and value arrays + const userKeys = Object.keys(this.user); + const userValues = userKeys.map(key => this.user[key]); + + // format data for Cognito user pool + userKeys.forEach((key, index) => { + if (key !== 'username' && key !== 'password' && key !== 'attributes') { + // needsPrefix determines if a custom attribute is indicated + // and prepends 'custom:' to the key before sending to Cognito if needed + const newKey = `${this.needPrefix(key) ? 'custom:' : ''}${key}`; + this.user.attributes[newKey] = userValues[index]; + } + }); + + let labelCheck = false; + this.signUpFields.forEach(field => { + if (field.label === this.getUsernameLabel()) { + this.amplifyService.logger( + `Changing the username to the value of ${field.label}`, + 'DEBUG' + ); + this.user.username = + this.user.attributes[field.key] || this.user.username; + labelCheck = true; + } + }); + if (!labelCheck && !this.user.username) { + // if the customer customized the username field in the sign up form + // He needs to either set the key of that field to 'username' + // Or make the label of the field the same as the 'usernameAttributes' + throw new Error( + `Couldn't find the label: ${this.getUsernameLabel()}, in sign up fields according to usernameAttributes!` + ); + } + + this.amplifyService + .auth() + .signUp(this.user) + .then(user => { + const username = this.user.username; + this.user = {}; + this.onAlertClose(); + this.amplifyService.setAuthState({ + state: 'confirmSignUp', + user: { username: username }, + }); + }) + .catch(err => this._setError(err)); + } + + onSignIn() { + this.onAlertClose(); + this.amplifyService.setAuthState({ state: 'signIn', user: null }); + } + + needPrefix(key) { + const field = this.signUpFields.find(e => e.key === key); + if (key.indexOf('custom:') !== 0) { + return field.custom; + } else if (key.indexOf('custom:') === 0 && field.custom === false) { + this.logger.warn( + 'Custom prefix prepended to key but custom field flag is set to false' + ); + } + return null; + } + + onConfirmSignUp() { + this.onAlertClose(); + this.amplifyService.setAuthState({ + state: 'confirmSignUp', + user: { username: this.user.username }, + }); + } + + sortFields() { + if (this.hiddenFields.length > 0) { + this.defaultSignUpFields = this.defaultSignUpFields.filter(d => { + return !this.hiddenFields.includes(d.key); + }); + } + + if ( + this._signUpConfig && + this._signUpConfig.signUpFields && + this._signUpConfig.signUpFields.length > 0 + ) { + if (!this._signUpConfig.hideAllDefaults) { + // see if fields passed to component should override defaults + this.defaultSignUpFields.forEach((f, i) => { + const matchKey = this.signUpFields.findIndex(d => { + return d.key === f.key; + }); + if (matchKey === -1) { + this.signUpFields.push(f); + } + }); + } + + /* sort fields based on following rules: 1. Fields with displayOrder are sorted before those without displayOrder 2. Fields with conflicting displayOrder are sorted alphabetically by key 3. Fields without displayOrder are sorted alphabetically by key */ - this.signUpFields.sort((a, b) => { - if (a.displayOrder && b.displayOrder) { - if (a.displayOrder < b.displayOrder) { - return -1; - } else if (a.displayOrder > b.displayOrder) { - return 1; - } else { - if (a.key < b.key) { - return -1; - } else { - return 1; - } - } - } else if (!a.displayOrder && b.displayOrder) { - return 1; - } else if (a.displayOrder && !b.displayOrder) { - return -1; - } else if (!a.displayOrder && !b.displayOrder) { - if (a.key < b.key) { - return -1; - } else { - return 1; - } - } - }); - this.signUpFields = this.removeHiddenFields(); - } - - } - - onAlertClose() { - this._setError(null); - } - - removeHiddenFields() { - return this.signUpFields.filter((f) => { - return !f.displayOrder || f.displayOrder !== -1; - }); - } - - validate() { - const invalids = []; - this.signUpFields.map((el) => { - if (el.key !== 'phone_number') { - if (el.required && !this.user[el.key]) { - el.invalid = true; - invalids.push(this.amplifyService.i18n().get(el.label)); - } else { - el.invalid = false; - } - } else { - if (el.required && (!this.country_code || !this.local_phone_number)) { - el.invalid = true; - invalids.push(this.amplifyService.i18n().get(el.label)); - } else { - el.invalid = false; - } - } - }); - return invalids; - } - - _setError(err) { - if (!err) { - this.errorMessage = null; - return; - } - - this.errorMessage = err.message || err; - } - - getUsernameLabel() { - return labelMap[this._usernameAttributes as string] || this._usernameAttributes; - } - - onPhoneFieldChanged(event: PhoneFieldOutput) { - this.country_code = event.country_code; - this.local_phone_number = event.local_phone_number; - } + this.signUpFields.sort((a, b) => { + if (a.displayOrder && b.displayOrder) { + if (a.displayOrder < b.displayOrder) { + return -1; + } else if (a.displayOrder > b.displayOrder) { + return 1; + } else { + if (a.key < b.key) { + return -1; + } else { + return 1; + } + } + } else if (!a.displayOrder && b.displayOrder) { + return 1; + } else if (a.displayOrder && !b.displayOrder) { + return -1; + } else if (!a.displayOrder && !b.displayOrder) { + if (a.key < b.key) { + return -1; + } else { + return 1; + } + } + }); + this.signUpFields = this.removeHiddenFields(); + } + } + + onAlertClose() { + this._setError(null); + } + + removeHiddenFields() { + return this.signUpFields.filter(f => { + return !f.displayOrder || f.displayOrder !== -1; + }); + } + + validate() { + const invalids = []; + this.signUpFields.map(el => { + if (el.key !== 'phone_number') { + if (el.required && !this.user[el.key]) { + el.invalid = true; + invalids.push(this.amplifyService.i18n().get(el.label)); + } else { + el.invalid = false; + } + } else { + if (el.required && (!this.country_code || !this.local_phone_number)) { + el.invalid = true; + invalids.push(this.amplifyService.i18n().get(el.label)); + } else { + el.invalid = false; + } + } + }); + return invalids; + } + + _setError(err) { + if (!err) { + this.errorMessage = null; + return; + } + + this.errorMessage = err.message || err; + } + + getUsernameLabel() { + return ( + labelMap[this._usernameAttributes as string] || this._usernameAttributes + ); + } + + onPhoneFieldChanged(event: PhoneFieldOutput) { + this.country_code = event.country_code; + this.local_phone_number = event.local_phone_number; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.component.ionic.ts b/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.component.ionic.ts index 3f34988bd24..fc73f07251b 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/sign-up-component/sign-up.component.ionic.ts @@ -20,7 +20,6 @@ import { SignUpComponentCore } from './sign-up.component.core'; import { countrylist, country } from '../../../assets/countries'; import { auth } from '../../../assets/data-test-attributes'; - const template = `
- -
- ` + selector: 'amplify-auth-sign-up', + template: ` +
+ +
+ `, }) export class SignUpComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() authState: AuthState; - @Input() signUpConfig: any; - @Input() usernameAttributes: string = 'username'; - @Input() hide: string[] = []; - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; + @Input() framework: string; + @Input() authState: AuthState; + @Input() signUpConfig: any; + @Input() usernameAttributes: string = 'username'; + @Input() hide: string[] = []; + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnInit() { - this.loadComponent(); - } + ngOnInit() { + this.loadComponent(); + } - ngOnDestroy() {} + ngOnDestroy() {} - loadComponent() { + loadComponent() { + const authComponent = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(SignUpComponentIonic, { + authState: this.authState, + signUpConfig: this.signUpConfig, + usernameAttributes: this.usernameAttributes, + hide: this.hide, + }) + : new ComponentMount(SignUpComponentCore, { + authState: this.authState, + signUpConfig: this.signUpConfig, + usernameAttributes: this.usernameAttributes, + hide: this.hide, + }); - const authComponent = this.framework && this.framework.toLowerCase() === 'ionic' ? - new ComponentMount(SignUpComponentIonic, { - authState: this.authState, - signUpConfig: this.signUpConfig, - usernameAttributes: this.usernameAttributes, - hide: this.hide, - }) : - new ComponentMount(SignUpComponentCore, { - authState: this.authState, - signUpConfig: this.signUpConfig, - usernameAttributes: this.usernameAttributes, - hide: this.hide, - }); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + authComponent.component + ); - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(authComponent.component); + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); - - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = authComponent.data; - } + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = authComponent.data; + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/types.ts b/packages/aws-amplify-angular/src/components/authenticator/types.ts index bf04452503b..a96a64ed229 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/types.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/types.ts @@ -1,17 +1,17 @@ export enum UsernameAttributes { - EMAIL = "email", - PHONE_NUMBER = "phone_number", - USERNAME = "username" + EMAIL = 'email', + PHONE_NUMBER = 'phone_number', + USERNAME = 'username', } export type UsernameFieldOutput = { - username?: string, - email?: string, - country_code?: string, - local_phone_number?: string -} + username?: string; + email?: string; + country_code?: string; + local_phone_number?: string; +}; export type PhoneFieldOutput = { - country_code: string, - local_phone_number: string -} + country_code: string; + local_phone_number: string; +}; diff --git a/packages/aws-amplify-angular/src/components/authenticator/username-field-component/username-field.component.core.ts b/packages/aws-amplify-angular/src/components/authenticator/username-field-component/username-field.component.core.ts index e908a02a599..6e2a3385ef2 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/username-field-component/username-field.component.core.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/username-field-component/username-field.component.core.ts @@ -13,9 +13,20 @@ */ // tslint:enable -import { Component, Input, OnInit, EventEmitter, Inject, Output } from '@angular/core'; +import { + Component, + Input, + OnInit, + EventEmitter, + Inject, + Output, +} from '@angular/core'; import { labelMap } from '../common'; -import { UsernameAttributes, UsernameFieldOutput, PhoneFieldOutput } from '../types'; +import { + UsernameAttributes, + UsernameFieldOutput, + PhoneFieldOutput, +} from '../types'; import { AmplifyService } from '../../../providers/amplify.service'; import { auth } from '../../../assets/data-test-attributes'; @@ -53,76 +64,85 @@ const template = ` `; @Component({ - selector: 'amplify-auth-username-field-core', - template, + selector: 'amplify-auth-username-field-core', + template, }) export class UsernameFieldComponentCore implements OnInit { - _usernameAttributes : string = UsernameAttributes.USERNAME; - _placeholder : string = ''; - username: string; + _usernameAttributes: string = UsernameAttributes.USERNAME; + _placeholder: string = ''; + username: string; - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - this.onPhoneFieldChanged = this.onPhoneFieldChanged.bind(this); - } + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + this.onPhoneFieldChanged = this.onPhoneFieldChanged.bind(this); + } - @Input() - set data(data: any) { - this._usernameAttributes = data.usernameAttributes; - this._placeholder = data.placeholder; - } + @Input() + set data(data: any) { + this._usernameAttributes = data.usernameAttributes; + this._placeholder = data.placeholder; + } - @Input() - set usernameAttributes(usernameAttributes: string) { - this._usernameAttributes = usernameAttributes; - } + @Input() + set usernameAttributes(usernameAttributes: string) { + this._usernameAttributes = usernameAttributes; + } - @Input() - set placeholder(placeholder: string) { - this._placeholder = placeholder; - } + @Input() + set placeholder(placeholder: string) { + this._placeholder = placeholder; + } - @Output() - usernameFieldChanged: EventEmitter = new EventEmitter(); + @Output() + usernameFieldChanged: EventEmitter = new EventEmitter< + UsernameFieldOutput + >(); - ngOnInit() { - if (window && - window.location && - window.location.search && - this._usernameAttributes !== 'email' && - this._usernameAttributes !== 'phone_number' - ) { - const searchParams = new URLSearchParams(window.location.search); - const username = searchParams ? searchParams.get('username') : undefined; - this.setUsername(username); - this.username = username; - } - } + ngOnInit() { + if ( + window && + window.location && + window.location.search && + this._usernameAttributes !== 'email' && + this._usernameAttributes !== 'phone_number' + ) { + const searchParams = new URLSearchParams(window.location.search); + const username = searchParams ? searchParams.get('username') : undefined; + this.setUsername(username); + this.username = username; + } + } - ngOnDestroy() {} + ngOnDestroy() {} - setUsername(username: string) { - this.usernameFieldChanged.emit({ - username - }); - } + setUsername(username: string) { + this.usernameFieldChanged.emit({ + username, + }); + } - setEmail(email: string) { - this.usernameFieldChanged.emit({ - email - }); - } + setEmail(email: string) { + this.usernameFieldChanged.emit({ + email, + }); + } - getUsernameLabel() { - return labelMap[this._usernameAttributes as string] || this._usernameAttributes; - } + getUsernameLabel() { + return ( + labelMap[this._usernameAttributes as string] || this._usernameAttributes + ); + } - getPlaceholder() { - return this.amplifyService.i18n().get(`${this.getUsernameLabel()}` || this._placeholder); - } + getPlaceholder() { + return this.amplifyService + .i18n() + .get(`${this.getUsernameLabel()}` || this._placeholder); + } - onPhoneFieldChanged(event: PhoneFieldOutput) { - this.usernameFieldChanged.emit({ - ...event - }); - } + onPhoneFieldChanged(event: PhoneFieldOutput) { + this.usernameFieldChanged.emit({ + ...event, + }); + } } diff --git a/packages/aws-amplify-angular/src/components/authenticator/username-field-component/username-field.component.ionic.ts b/packages/aws-amplify-angular/src/components/authenticator/username-field-component/username-field.component.ionic.ts index 709387a4b2c..7706e4ec4a1 100644 --- a/packages/aws-amplify-angular/src/components/authenticator/username-field-component/username-field.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/authenticator/username-field-component/username-field.component.ionic.ts @@ -51,12 +51,13 @@ const template = ` `; @Component({ - selector: 'amplify-auth-username-field-ionic', - template, + selector: 'amplify-auth-username-field-ionic', + template, }) export class UsernameFieldComponentIonic extends UsernameFieldComponentCore { - - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - super(amplifyService); - } + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + super(amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/common/form.component.ts b/packages/aws-amplify-angular/src/components/common/form.component.ts index 74d83cf819b..359cfc55a8f 100644 --- a/packages/aws-amplify-angular/src/components/common/form.component.ts +++ b/packages/aws-amplify-angular/src/components/common/form.component.ts @@ -27,15 +27,15 @@ const template = ` -` +`; @Component({ - selector: 'amplify-form', - template: template + selector: 'amplify-form', + template: template, }) export class FormComponent { - @Input() - set title(title: string) { - this.title = title; - } + @Input() + set title(title: string) { + this.title = title; + } } diff --git a/packages/aws-amplify-angular/src/components/component.mount.ts b/packages/aws-amplify-angular/src/components/component.mount.ts index 2e57828c5ba..5c876b6c300 100644 --- a/packages/aws-amplify-angular/src/components/component.mount.ts +++ b/packages/aws-amplify-angular/src/components/component.mount.ts @@ -16,5 +16,5 @@ import { Type } from '@angular/core'; export class ComponentMount { - constructor(public component: Type, public data: any) {} + constructor(public component: Type, public data: any) {} } diff --git a/packages/aws-amplify-angular/src/components/interactions/chatbot/aws-lex-audio.js b/packages/aws-amplify-angular/src/components/interactions/chatbot/aws-lex-audio.js index 9c64b88dcb3..42740dcaff5 100644 --- a/packages/aws-amplify-angular/src/components/interactions/chatbot/aws-lex-audio.js +++ b/packages/aws-amplify-angular/src/components/interactions/chatbot/aws-lex-audio.js @@ -12,793 +12,977 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o amplitude || curr_value_time < (-1 * amplitude)) { - start = Date.now(); - } - } - var newtime = Date.now(); - var elapsedTime = newtime - start; - if (elapsedTime > time) { - silenceCallback(); - } - }; - - /** - * The onaudioprocess event handler of the ScriptProcessorNode interface. It is the EventHandler to be - * called for the audioprocess event that is dispatched to ScriptProcessorNode node types. - * @param {AudioProcessingEvent} audioProcessingEvent - The audio processing event. - */ - node.onaudioprocess = function (audioProcessingEvent) { - if (!recording) { - return; - } - worker.postMessage({ - command: 'record', - buffer: [ - audioProcessingEvent.inputBuffer.getChannelData(0), - ] - }); - analyse(); - }; - - var analyser = source.context.createAnalyser(); - analyser.minDecibels = -90; - analyser.maxDecibels = -10; - analyser.smoothingTimeConstant = 0.85; - - source.connect(analyser); - analyser.connect(node); - node.connect(source.context.destination); - - return { - record: record, - stop: stop, - clear: clear, - exportWAV: exportWAV - }; - }; - - /** - * Audio recorder object. Handles setting up the audio context, - * accessing the mike, and creating the Recorder object. - */ - exports.audioRecorder = function () { - - /** - * Creates an audio context and calls getUserMedia to request the mic (audio). - */ - var requestDevice = function () { - - if (typeof audio_context === 'undefined') { - window.AudioContext = window.AudioContext || window.webkitAudioContext; - audio_context = new AudioContext(); - } - - return navigator.mediaDevices.getUserMedia({audio: true}).then(function (stream) { - audio_stream = stream; - }); - }; - - var createRecorder = function (silenceDetectionConfig) { - return recorder(audio_context.createMediaStreamSource(audio_stream), silenceDetectionConfig); - }; - - var audioContext = function () { - return audio_context; - }; - - return { - requestDevice: requestDevice, - createRecorder: createRecorder, - audioContext: audioContext - }; - - }; -})(); -},{"./worker.js":6,"webworkify":4}],6:[function(require,module,exports){ -module.exports = function (self) { - 'use strict'; - var recLength = 0, - recBuffer = [], - recordSampleRate; - - self.addEventListener('message', function (e) { - switch (e.data.command) { - case 'init': - init(e.data.config); - break; - case 'record': - record(e.data.buffer); - break; - case 'export': - exportBuffer(e.data.sampleRate); - break; - case 'clear': - clear(); - break; - } - }); - - function init(config) { - recordSampleRate = config.sampleRate; - } - - function record(inputBuffer) { - recBuffer.push(inputBuffer[0]); - recLength += inputBuffer[0].length; - } - - function exportBuffer(exportSampleRate) { - var mergedBuffers = mergeBuffers(recBuffer, recLength); - var downsampledBuffer = downsampleBuffer(mergedBuffers, exportSampleRate); - var encodedWav = encodeWAV(downsampledBuffer); - var audioBlob = new Blob([encodedWav], {type: 'application/octet-stream'}); - postMessage(audioBlob); - } - - function clear() { - recLength = 0; - recBuffer = []; - } - - function downsampleBuffer(buffer, exportSampleRate) { - if (exportSampleRate === recordSampleRate) { - return buffer; - } - var sampleRateRatio = recordSampleRate / exportSampleRate; - var newLength = Math.round(buffer.length / sampleRateRatio); - var result = new Float32Array(newLength); - var offsetResult = 0; - var offsetBuffer = 0; - while (offsetResult < result.length) { - var nextOffsetBuffer = Math.round((offsetResult + 1) * sampleRateRatio); - var accum = 0, - count = 0; - for (var i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) { - accum += buffer[i]; - count++; - } - result[offsetResult] = accum / count; - offsetResult++; - offsetBuffer = nextOffsetBuffer; - } - return result; - } - - function mergeBuffers(bufferArray, recLength) { - var result = new Float32Array(recLength); - var offset = 0; - for (var i = 0; i < bufferArray.length; i++) { - result.set(bufferArray[i], offset); - offset += bufferArray[i].length; - } - return result; - } - - function floatTo16BitPCM(output, offset, input) { - for (var i = 0; i < input.length; i++, offset += 2) { - var s = Math.max(-1, Math.min(1, input[i])); - output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true); - } - } - - function writeString(view, offset, string) { - for (var i = 0; i < string.length; i++) { - view.setUint8(offset + i, string.charCodeAt(i)); - } - } - - function encodeWAV(samples) { - var buffer = new ArrayBuffer(44 + samples.length * 2); - var view = new DataView(buffer); - - writeString(view, 0, 'RIFF'); - view.setUint32(4, 32 + samples.length * 2, true); - writeString(view, 8, 'WAVE'); - writeString(view, 12, 'fmt '); - view.setUint32(16, 16, true); - view.setUint16(20, 1, true); - view.setUint16(22, 1, true); - view.setUint32(24, recordSampleRate, true); - view.setUint32(28, recordSampleRate * 2, true); - view.setUint16(32, 2, true); - view.setUint16(34, 16, true); - writeString(view, 36, 'data'); - view.setUint32(40, samples.length * 2, true); - floatTo16BitPCM(view, 44, samples); - - return view; - } -}; - -},{}]},{},[3]); +(function e(t, n, r) { + function s(o, u) { + if (!n[o]) { + if (!t[o]) { + var a = typeof require == 'function' && require; + if (!u && a) return a(o, !0); + if (i) return i(o, !0); + var f = new Error("Cannot find module '" + o + "'"); + throw ((f.code = 'MODULE_NOT_FOUND'), f); + } + var l = (n[o] = { exports: {} }); + t[o][0].call( + l.exports, + function(e) { + var n = t[o][1][e]; + return s(n ? n : e); + }, + l, + l.exports, + e, + t, + n, + r + ); + } + return n[o].exports; + } + var i = typeof require == 'function' && require; + for (var o = 0; o < r.length; o++) s(r[o]); + return s; +})( + { + 1: [ + function(require, module, exports) { + (function() { + 'use strict'; + var rec = require('./recorder.js'); + var recorder, + audioRecorder, + checkAudioSupport, + audioSupported, + playbackSource, + UNSUPPORTED = 'Audio is not supported.'; + + /** + * Represents an audio control that can start and stop recording, + * export captured audio, play an audio buffer, and check if audio + * is supported. + */ + exports.audioControl = function(options) { + options = options || {}; + this.checkAudioSupport = options.checkAudioSupport !== false; + + /** + * This callback type is called `onSilenceCallback`. + * + * @callback onSilenceCallback + */ + + /** + * Visualize callback: `visualizerCallback`. + * + * @callback visualizerCallback + * @param {Uint8Array} dataArray + * @param {number} bufferLength + */ + + /** + * Clears the previous buffer and starts buffering audio. + * + * @param {?onSilenceCallback} onSilence - Called when silence is detected. + * @param {?visualizerCallback} visualizer - Can be used to visualize the captured buffer. + * @param {silenceDetectionConfig} - Specify custom silence detection values. + * @throws {Error} If audio is not supported. + */ + var startRecording = function( + onSilence, + visualizer, + silenceDetectionConfig + ) { + onSilence = + onSilence || + function() { + /* no op */ + }; + visualizer = + visualizer || + function() { + /* no op */ + }; + audioSupported = audioSupported !== false; + if (!audioSupported) { + throw new Error(UNSUPPORTED); + } + recorder = audioRecorder.createRecorder(silenceDetectionConfig); + recorder.record(onSilence, visualizer); + }; + + /** + * Stops buffering audio. + * + * @throws {Error} If audio is not supported. + */ + var stopRecording = function() { + audioSupported = audioSupported !== false; + if (!audioSupported) { + throw new Error(UNSUPPORTED); + } + recorder.stop(); + }; + + /** + * On export complete callback: `onExportComplete`. + * + * @callback onExportComplete + * @param {Blob} blob The exported audio as a Blob. + */ + + /** + * Exports the captured audio buffer. + * + * @param {onExportComplete} callback - Called when the export is complete. + * @param {sampleRate} The sample rate to use in the export. + * @throws {Error} If audio is not supported. + */ + var exportWAV = function(callback, sampleRate) { + audioSupported = audioSupported !== false; + if (!audioSupported) { + throw new Error(UNSUPPORTED); + } + if (!(callback && typeof callback === 'function')) { + throw new Error('You must pass a callback function to export.'); + } + sampleRate = + typeof sampleRate !== 'undefined' ? sampleRate : 16000; + recorder.exportWAV(callback, sampleRate); + recorder.clear(); + }; + + /** + * On playback complete callback: `onPlaybackComplete`. + * + * @callback onPlaybackComplete + */ + + /** + * Plays the audio buffer with an HTML5 audio tag. + * @param {Uint8Array} buffer - The audio buffer to play. + * @param {?onPlaybackComplete} callback - Called when audio playback is complete. + */ + var playHtmlAudioElement = function(buffer, callback) { + if (typeof buffer === 'undefined') { + return; + } + var myBlob = new Blob([buffer]); + var audio = document.createElement('audio'); + var objectUrl = window.URL.createObjectURL(myBlob); + audio.src = objectUrl; + audio.addEventListener('ended', function() { + audio.currentTime = 0; + if (typeof callback === 'function') { + callback(); + } + }); + audio.play(); + }; + + /** + * On playback complete callback: `onPlaybackComplete`. + * + * @callback onPlaybackComplete + */ + + /** + * Plays the audio buffer with a WebAudio AudioBufferSourceNode. + * @param {Uint8Array} buffer - The audio buffer to play. + * @param {?onPlaybackComplete} callback - Called when audio playback is complete. + */ + var play = function(buffer, callback) { + if (typeof buffer === 'undefined') { + return; + } + var myBlob = new Blob([buffer]); + // We'll use a FileReader to create and ArrayBuffer out of the audio response. + var fileReader = new FileReader(); + fileReader.onload = function() { + // Once we have an ArrayBuffer we can create our BufferSource and decode the result as an AudioBuffer. + playbackSource = audioRecorder + .audioContext() + .createBufferSource(); + audioRecorder + .audioContext() + .decodeAudioData(this.result, function(buf) { + // Set the source buffer as our new AudioBuffer. + playbackSource.buffer = buf; + // Set the destination (the actual audio-rendering device--your device's speakers). + playbackSource.connect( + audioRecorder.audioContext().destination + ); + // Add an "on ended" callback. + playbackSource.onended = function(event) { + if (typeof callback === 'function') { + callback(); + } + }; + // Start the playback. + playbackSource.start(0); + }); + }; + fileReader.readAsArrayBuffer(myBlob); + }; + + /** + * Stops the playback source (created by the play method) if it exists. The `onPlaybackComplete` + * callback will be called. + */ + var stop = function() { + if (typeof playbackSource === 'undefined') { + return; + } + playbackSource.stop(); + }; + + /** + * Clear the recording buffer. + */ + var clear = function() { + recorder.clear(); + }; + + /** + * On audio supported callback: `onAudioSupported`. + * + * @callback onAudioSupported + * @param {boolean} + */ + + /** + * Checks that getUserMedia is supported and the user has given us access to the mic. + * @param {onAudioSupported} callback - Called with the result. + */ + var supportsAudio = function(callback) { + callback = + callback || + function() { + /* no op */ + }; + if ( + navigator.mediaDevices && + navigator.mediaDevices.getUserMedia + ) { + audioRecorder = rec.audioRecorder(); + audioRecorder + .requestDevice() + .then(function(stream) { + audioSupported = true; + callback(audioSupported); + }) + .catch(function(error) { + audioSupported = false; + callback(audioSupported); + }); + } else { + audioSupported = false; + callback(audioSupported); + } + }; + + if (this.checkAudioSupport) { + supportsAudio(); + } + + return { + startRecording: startRecording, + stopRecording: stopRecording, + exportWAV: exportWAV, + play: play, + stop: stop, + clear: clear, + playHtmlAudioElement: playHtmlAudioElement, + supportsAudio: supportsAudio, + }; + }; + })(); + }, + { './recorder.js': 5 }, + ], + 2: [ + function(require, module, exports) { + (function() { + 'use strict'; + var AudioControl = require('./control.js').audioControl; + + var DEFAULT_LATEST = '$LATEST'; + var DEFAULT_CONTENT_TYPE = 'audio/x-l16; sample-rate=16000'; + var DEFAULT_USER_ID = 'userId'; + var DEFAULT_ACCEPT_HEADER_VALUE = 'audio/mpeg'; + var MESSAGES = Object.freeze({ + PASSIVE: 'Passive', + LISTENING: 'Listening', + SENDING: 'Sending', + SPEAKING: 'Speaking', + }); + + var lexruntime, + audioControl = new AudioControl({ checkAudioSupport: false }); + + exports.conversation = function( + config, + onStateChange, + onSuccess, + onError, + onAudioData + ) { + var currentState; + + // Apply default values. + this.config = applyDefaults(config); + this.lexConfig = this.config.lexConfig; + this.messages = MESSAGES; + onStateChange = + onStateChange || + function() { + /* no op */ + }; + this.onSuccess = + onSuccess || + function() { + /* no op */ + }; + this.onError = + onError || + function() { + /* no op */ + }; + this.onAudioData = + onAudioData || + function() { + /* no op */ + }; + + // Validate input. + if (!this.config.lexConfig.botName) { + this.onError('A Bot name must be provided.'); + return; + } + if (!AWS.config.credentials) { + this.onError('AWS Credentials must be provided.'); + return; + } + if (!AWS.config.region) { + this.onError('A Region value must be provided.'); + return; + } + + lexruntime = new AWS.LexRuntime(); + + this.onSilence = function() { + if (config.silenceDetection) { + audioControl.stopRecording(); + currentState.advanceConversation(); + } + }; + + this.transition = function(conversation) { + currentState = conversation; + var state = currentState.state; + onStateChange(state.message); + + // If we are transitioning into SENDING or SPEAKING we want to immediately advance the conversation state + // to start the service call or playback. + if ( + state.message === state.messages.SENDING || + state.message === state.messages.SPEAKING + ) { + currentState.advanceConversation(); + } + // If we are transitioning in to sending and we are not detecting silence (this was a manual state change) + // we need to do some cleanup: stop recording, and stop rendering. + if ( + state.message === state.messages.SENDING && + !this.config.silenceDetection + ) { + audioControl.stopRecording(); + } + }; + + this.advanceConversation = function() { + audioControl.supportsAudio(function(supported) { + if (supported) { + currentState.advanceConversation(); + } else { + onError('Audio is not supported.'); + } + }); + }; + + this.updateConfig = function(newValue) { + this.config = applyDefaults(newValue); + this.lexConfig = this.config.lexConfig; + }; + + this.reset = function() { + audioControl.clear(); + currentState = new Initial(currentState.state); + }; + + currentState = new Initial(this); + + return { + advanceConversation: this.advanceConversation, + updateConfig: this.updateConfig, + reset: this.reset, + }; + }; + + var Initial = function(state) { + this.state = state; + state.message = state.messages.PASSIVE; + this.advanceConversation = function() { + audioControl.startRecording( + state.onSilence, + state.onAudioData, + state.config.silenceDetectionConfig + ); + state.transition(new Listening(state)); + }; + }; + + var Listening = function(state) { + this.state = state; + state.message = state.messages.LISTENING; + this.advanceConversation = function() { + audioControl.exportWAV(function(blob) { + state.audioInput = blob; + state.transition(new Sending(state)); + }); + }; + }; + + var Sending = function(state) { + this.state = state; + state.message = state.messages.SENDING; + this.advanceConversation = function() { + state.lexConfig.inputStream = state.audioInput; + lexruntime.postContent(state.lexConfig, function(err, data) { + if (err) { + state.onError(err); + state.transition(new Initial(state)); + } else { + state.audioOutput = data; + state.transition(new Speaking(state)); + state.onSuccess(data); + } + }); + }; + }; + + var Speaking = function(state) { + this.state = state; + state.message = state.messages.SPEAKING; + this.advanceConversation = function() { + if (state.audioOutput.contentType === 'audio/mpeg') { + audioControl.play(state.audioOutput.audioStream, function() { + if ( + state.audioOutput.dialogState === 'ReadyForFulfillment' || + state.audioOutput.dialogState === 'Fulfilled' || + state.audioOutput.dialogState === 'Failed' || + !state.config.silenceDetection + ) { + state.transition(new Initial(state)); + } else { + audioControl.startRecording( + state.onSilence, + state.onAudioData, + state.config.silenceDetectionConfig + ); + state.transition(new Listening(state)); + } + }); + } else { + state.transition(new Initial(state)); + } + }; + }; + + var applyDefaults = function(config) { + config = config || {}; + config.silenceDetection = config.hasOwnProperty('silenceDetection') + ? config.silenceDetection + : true; + + var lexConfig = config.lexConfig || {}; + lexConfig.botAlias = lexConfig.hasOwnProperty('botAlias') + ? lexConfig.botAlias + : DEFAULT_LATEST; + lexConfig.botName = lexConfig.hasOwnProperty('botName') + ? lexConfig.botName + : ''; + lexConfig.contentType = lexConfig.hasOwnProperty('contentType') + ? lexConfig.contentType + : DEFAULT_CONTENT_TYPE; + lexConfig.userId = lexConfig.hasOwnProperty('userId') + ? lexConfig.userId + : DEFAULT_USER_ID; + lexConfig.accept = lexConfig.hasOwnProperty('accept') + ? lexConfig.accept + : DEFAULT_ACCEPT_HEADER_VALUE; + config.lexConfig = lexConfig; + + return config; + }; + })(); + }, + { './control.js': 1 }, + ], + 3: [ + function(require, module, exports) { + (function(global) { + /** + * @module LexAudio + * @description The global namespace for Amazon Lex Audio + */ + global.LexAudio = global.LexAudio || {}; + global.LexAudio.audioControl = require('./control.js').audioControl; + global.LexAudio.conversation = require('./conversation.js').conversation; + module.exports = global.LexAudio; + }.call( + this, + typeof global !== 'undefined' + ? global + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : {} + )); + }, + { './control.js': 1, './conversation.js': 2 }, + ], + 4: [ + function(require, module, exports) { + var bundleFn = arguments[3]; + var sources = arguments[4]; + var cache = arguments[5]; + + var stringify = JSON.stringify; + + module.exports = function(fn, options) { + var wkey; + var cacheKeys = Object.keys(cache); + + for (var i = 0, l = cacheKeys.length; i < l; i++) { + var key = cacheKeys[i]; + var exp = cache[key].exports; + // Using babel as a transpiler to use esmodule, the export will always + // be an object with the default export as a property of it. To ensure + // the existing api and babel esmodule exports are both supported we + // check for both + if (exp === fn || (exp && exp.default === fn)) { + wkey = key; + break; + } + } + + if (!wkey) { + wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); + var wcache = {}; + for (var i = 0, l = cacheKeys.length; i < l; i++) { + var key = cacheKeys[i]; + wcache[key] = key; + } + sources[wkey] = [ + Function(['require', 'module', 'exports'], '(' + fn + ')(self)'), + wcache, + ]; + } + var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); + + var scache = {}; + scache[wkey] = wkey; + sources[skey] = [ + Function( + ['require'], + // try to call default if defined to also support babel esmodule + // exports + 'var f = require(' + + stringify(wkey) + + ');' + + '(f.default ? f.default : f)(self);' + ), + scache, + ]; + + var workerSources = {}; + resolveSources(skey); + + function resolveSources(key) { + workerSources[key] = true; + + for (var depPath in sources[key][1]) { + var depKey = sources[key][1][depPath]; + if (!workerSources[depKey]) { + resolveSources(depKey); + } + } + } + + var src = + '(' + + bundleFn + + ')({' + + Object.keys(workerSources) + .map(function(key) { + return ( + stringify(key) + + ':[' + + sources[key][0] + + ',' + + stringify(sources[key][1]) + + ']' + ); + }) + .join(',') + + '},{},[' + + stringify(skey) + + '])'; + var URL = + window.URL || window.webkitURL || window.mozURL || window.msURL; + + var blob = new Blob([src], { type: 'text/javascript' }); + if (options && options.bare) { + return blob; + } + var workerUrl = URL.createObjectURL(blob); + var worker = new Worker(workerUrl); + worker.objectURL = workerUrl; + return worker; + }; + }, + {}, + ], + 5: [ + function(require, module, exports) { + (function() { + 'use strict'; + var work = require('webworkify'); + var worker = work(require('./worker.js')); + var audio_context, audio_stream; + + /** + * The Recorder object. Sets up the onaudioprocess callback and communicates + * with the web worker to perform audio actions. + */ + var recorder = function(source, silenceDetectionConfig) { + silenceDetectionConfig = silenceDetectionConfig || {}; + silenceDetectionConfig.time = silenceDetectionConfig.hasOwnProperty( + 'time' + ) + ? silenceDetectionConfig.time + : 1500; + silenceDetectionConfig.amplitude = silenceDetectionConfig.hasOwnProperty( + 'amplitude' + ) + ? silenceDetectionConfig.amplitude + : 0.2; + + var recording = false, + currCallback, + start, + silenceCallback, + visualizationCallback; + + // Create a ScriptProcessorNode with a bufferSize of 4096 and a single input and output channel + var node = source.context.createScriptProcessor(4096, 1, 1); + + worker.onmessage = function(message) { + var blob = message.data; + currCallback(blob); + }; + + worker.postMessage({ + command: 'init', + config: { + sampleRate: source.context.sampleRate, + }, + }); + + /** + * Sets the silence and viz callbacks, resets the silence start time, and sets recording to true. + * @param {?onSilenceCallback} onSilence - Called when silence is detected. + * @param {?visualizerCallback} visualizer - Can be used to visualize the captured buffer. + */ + var record = function(onSilence, visualizer) { + silenceCallback = onSilence; + visualizationCallback = visualizer; + start = Date.now(); + recording = true; + }; + + /** + * Sets recording to false. + */ + var stop = function() { + recording = false; + }; + + /** + * Posts "clear" message to the worker. + */ + var clear = function() { + stop(); + worker.postMessage({ command: 'clear' }); + }; + + /** + * Sets the export callback and posts an "export" message to the worker. + * @param {onExportComplete} callback - Called when the export is complete. + * @param {sampleRate} The sample rate to use in the export. + */ + var exportWAV = function(callback, sampleRate) { + currCallback = callback; + worker.postMessage({ + command: 'export', + sampleRate: sampleRate, + }); + }; + + /** + * Checks the time domain data to see if the amplitude of the audio waveform is more than + * the silence threshold. If it is, "noise" has been detected and it resets the start time. + * If the elapsed time reaches the time threshold the silence callback is called. If there is a + * visualizationCallback it invokes the visualization callback with the time domain data. + */ + var analyse = function() { + analyser.fftSize = 2048; + var bufferLength = analyser.fftSize; + var dataArray = new Uint8Array(bufferLength); + var amplitude = silenceDetectionConfig.amplitude; + var time = silenceDetectionConfig.time; + + analyser.getByteTimeDomainData(dataArray); + + if (typeof visualizationCallback === 'function') { + visualizationCallback(dataArray, bufferLength); + } + + for (var i = 0; i < bufferLength; i++) { + // Normalize between -1 and 1. + var curr_value_time = dataArray[i] / 128 - 1.0; + if ( + curr_value_time > amplitude || + curr_value_time < -1 * amplitude + ) { + start = Date.now(); + } + } + var newtime = Date.now(); + var elapsedTime = newtime - start; + if (elapsedTime > time) { + silenceCallback(); + } + }; + + /** + * The onaudioprocess event handler of the ScriptProcessorNode interface. It is the EventHandler to be + * called for the audioprocess event that is dispatched to ScriptProcessorNode node types. + * @param {AudioProcessingEvent} audioProcessingEvent - The audio processing event. + */ + node.onaudioprocess = function(audioProcessingEvent) { + if (!recording) { + return; + } + worker.postMessage({ + command: 'record', + buffer: [audioProcessingEvent.inputBuffer.getChannelData(0)], + }); + analyse(); + }; + + var analyser = source.context.createAnalyser(); + analyser.minDecibels = -90; + analyser.maxDecibels = -10; + analyser.smoothingTimeConstant = 0.85; + + source.connect(analyser); + analyser.connect(node); + node.connect(source.context.destination); + + return { + record: record, + stop: stop, + clear: clear, + exportWAV: exportWAV, + }; + }; + + /** + * Audio recorder object. Handles setting up the audio context, + * accessing the mike, and creating the Recorder object. + */ + exports.audioRecorder = function() { + /** + * Creates an audio context and calls getUserMedia to request the mic (audio). + */ + var requestDevice = function() { + if (typeof audio_context === 'undefined') { + window.AudioContext = + window.AudioContext || window.webkitAudioContext; + audio_context = new AudioContext(); + } + + return navigator.mediaDevices + .getUserMedia({ audio: true }) + .then(function(stream) { + audio_stream = stream; + }); + }; + + var createRecorder = function(silenceDetectionConfig) { + return recorder( + audio_context.createMediaStreamSource(audio_stream), + silenceDetectionConfig + ); + }; + + var audioContext = function() { + return audio_context; + }; + + return { + requestDevice: requestDevice, + createRecorder: createRecorder, + audioContext: audioContext, + }; + }; + })(); + }, + { './worker.js': 6, webworkify: 4 }, + ], + 6: [ + function(require, module, exports) { + module.exports = function(self) { + 'use strict'; + var recLength = 0, + recBuffer = [], + recordSampleRate; + + self.addEventListener('message', function(e) { + switch (e.data.command) { + case 'init': + init(e.data.config); + break; + case 'record': + record(e.data.buffer); + break; + case 'export': + exportBuffer(e.data.sampleRate); + break; + case 'clear': + clear(); + break; + } + }); + + function init(config) { + recordSampleRate = config.sampleRate; + } + + function record(inputBuffer) { + recBuffer.push(inputBuffer[0]); + recLength += inputBuffer[0].length; + } + + function exportBuffer(exportSampleRate) { + var mergedBuffers = mergeBuffers(recBuffer, recLength); + var downsampledBuffer = downsampleBuffer( + mergedBuffers, + exportSampleRate + ); + var encodedWav = encodeWAV(downsampledBuffer); + var audioBlob = new Blob([encodedWav], { + type: 'application/octet-stream', + }); + postMessage(audioBlob); + } + + function clear() { + recLength = 0; + recBuffer = []; + } + + function downsampleBuffer(buffer, exportSampleRate) { + if (exportSampleRate === recordSampleRate) { + return buffer; + } + var sampleRateRatio = recordSampleRate / exportSampleRate; + var newLength = Math.round(buffer.length / sampleRateRatio); + var result = new Float32Array(newLength); + var offsetResult = 0; + var offsetBuffer = 0; + while (offsetResult < result.length) { + var nextOffsetBuffer = Math.round( + (offsetResult + 1) * sampleRateRatio + ); + var accum = 0, + count = 0; + for ( + var i = offsetBuffer; + i < nextOffsetBuffer && i < buffer.length; + i++ + ) { + accum += buffer[i]; + count++; + } + result[offsetResult] = accum / count; + offsetResult++; + offsetBuffer = nextOffsetBuffer; + } + return result; + } + + function mergeBuffers(bufferArray, recLength) { + var result = new Float32Array(recLength); + var offset = 0; + for (var i = 0; i < bufferArray.length; i++) { + result.set(bufferArray[i], offset); + offset += bufferArray[i].length; + } + return result; + } + + function floatTo16BitPCM(output, offset, input) { + for (var i = 0; i < input.length; i++, offset += 2) { + var s = Math.max(-1, Math.min(1, input[i])); + output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true); + } + } + + function writeString(view, offset, string) { + for (var i = 0; i < string.length; i++) { + view.setUint8(offset + i, string.charCodeAt(i)); + } + } + + function encodeWAV(samples) { + var buffer = new ArrayBuffer(44 + samples.length * 2); + var view = new DataView(buffer); + + writeString(view, 0, 'RIFF'); + view.setUint32(4, 32 + samples.length * 2, true); + writeString(view, 8, 'WAVE'); + writeString(view, 12, 'fmt '); + view.setUint32(16, 16, true); + view.setUint16(20, 1, true); + view.setUint16(22, 1, true); + view.setUint32(24, recordSampleRate, true); + view.setUint32(28, recordSampleRate * 2, true); + view.setUint16(32, 2, true); + view.setUint16(34, 16, true); + writeString(view, 36, 'data'); + view.setUint32(40, samples.length * 2, true); + floatTo16BitPCM(view, 44, samples); + + return view; + } + }; + }, + {}, + ], + }, + {}, + [3] +); diff --git a/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.class.ts b/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.class.ts index 2eafde44040..6601496eaf3 100644 --- a/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.class.ts +++ b/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.class.ts @@ -14,5 +14,5 @@ // tslint:enable export class ChatBotClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.component.core.ts b/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.component.core.ts index 7b25f40ab0e..616c728833b 100644 --- a/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.component.core.ts +++ b/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.component.core.ts @@ -20,13 +20,12 @@ import { EventEmitter, OnInit, ChangeDetectorRef, - Inject + Inject, } from '@angular/core'; import { AmplifyService } from '../../../providers/amplify.service'; import { isUndefined } from 'util'; require('./aws-lex-audio.js'); - const template = `
@@ -86,23 +85,23 @@ const STATES = { INITIAL: { MESSAGE: 'Type your message or click 🎤', ICON: '🎤' }, LISTENING: { MESSAGE: 'Listening... click 🔴 again to cancel', ICON: '🔴' }, SENDING: { MESSAGE: 'Please wait...', ICON: '🔊' }, - SPEAKING: { MESSAGE: 'Speaking...', ICON: '...' } + SPEAKING: { MESSAGE: 'Speaking...', ICON: '...' }, }; const defaultVoiceConfig = { silenceDetectionConfig: { time: 2000, - amplitude: 0.2 - } + amplitude: 0.2, + }, }; @Component({ selector: 'amplify-interactions-core', - template + template, }) -export class ChatbotComponentCore implements OnInit { +export class ChatbotComponentCore implements OnInit { errorMessage: string; - inputText: string = ""; + inputText: string = ''; botName: string; chatTitle: string; clearComplete: boolean = false; @@ -126,7 +125,10 @@ export class ChatbotComponentCore implements OnInit { @Output() complete: EventEmitter = new EventEmitter(); - constructor(ref: ChangeDetectorRef, @Inject(AmplifyService) protected amplifyService: AmplifyService) { + constructor( + ref: ChangeDetectorRef, + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { this.ref = ref; this.continueConversation = false; this.logger = this.amplifyService.logger('ChatbotComponent'); @@ -137,21 +139,27 @@ export class ChatbotComponentCore implements OnInit { this.botName = data.bot; this.chatTitle = data.title; this.clearComplete = data.clearComplete; - this.conversationModeOn = isUndefined(data.conversationModeOn) ? false : data.conversationModeOn; - this.voiceEnabled = isUndefined(data.voiceEnabled) ? false : data.voiceEnabled; + this.conversationModeOn = isUndefined(data.conversationModeOn) + ? false + : data.conversationModeOn; + this.voiceEnabled = isUndefined(data.voiceEnabled) + ? false + : data.voiceEnabled; this.textEnabled = isUndefined(data.textEnabled) ? true : data.textEnabled; this.voiceConfig = data.voiceConfig || this.voiceConfig; this.performOnComplete = this.performOnComplete.bind(this); - this.amplifyService.interactions().onComplete(this.botName, this.performOnComplete); + this.amplifyService + .interactions() + .onComplete(this.botName, this.performOnComplete); if (!this.textEnabled && this.voiceEnabled) { - this.currentVoiceState = "Click the mic button"; - STATES.INITIAL.MESSAGE = "Click the mic button"; + this.currentVoiceState = 'Click the mic button'; + STATES.INITIAL.MESSAGE = 'Click the mic button'; } if (!this.voiceEnabled && this.textEnabled) { - this.currentVoiceState = "Type a message"; - STATES.INITIAL.MESSAGE = "Type a message"; + this.currentVoiceState = 'Type a message'; + STATES.INITIAL.MESSAGE = 'Type a message'; } if (this.voiceEnabled) { @@ -159,12 +167,13 @@ export class ChatbotComponentCore implements OnInit { } } - @Input() set bot(botName: string) { this.botName = botName; this.performOnComplete = this.performOnComplete.bind(this); - this.amplifyService.interactions().onComplete(botName, this.performOnComplete); + this.amplifyService + .interactions() + .onComplete(botName, this.performOnComplete); } @Input() @@ -178,10 +187,12 @@ export class ChatbotComponentCore implements OnInit { } ngOnInit() { - if (!this.amplifyService.interactions()){ - throw new Error('Interactions module not registered on AmplifyService provider'); - } - } + if (!this.amplifyService.interactions()) { + throw new Error( + 'Interactions module not registered on AmplifyService provider' + ); + } + } performOnComplete(evt) { this.complete.emit(evt); @@ -199,26 +210,28 @@ export class ChatbotComponentCore implements OnInit { return; } const message = { - 'me': this.inputText, - 'meSentTime': new Date().toLocaleTimeString(), - 'bot': '', - 'botSentTime': '' + me: this.inputText, + meSentTime: new Date().toLocaleTimeString(), + bot: '', + botSentTime: '', }; - this.amplifyService.interactions().send(this.botName, this.inputText) + this.amplifyService + .interactions() + .send(this.botName, this.inputText) .then((response: any) => { - this.inputText = ""; + this.inputText = ''; message.bot = response.message; message.botSentTime = new Date().toLocaleTimeString(); this.messages.push(message); }) - .catch((error) => this.logger.error(error)); + .catch(error => this.logger.error(error)); } onSilenceHandler = () => { if (!this.continueConversation) { return; } - this.audioControl.exportWAV((blob) => { + this.audioControl.exportWAV(blob => { this.currentVoiceState = STATES.SENDING.MESSAGE; this.audioInput = blob; this.micText = STATES.SENDING.ICON; @@ -226,7 +239,7 @@ export class ChatbotComponentCore implements OnInit { this.lexResponseHandler(); }); this.ref.detectChanges(); - } + }; reset() { this.audioControl.clear(); @@ -248,14 +261,16 @@ export class ChatbotComponentCore implements OnInit { return; } - const interactionsMessage = { - content: this.audioInput, - options: { - messageType: 'voice' - } + const interactionsMessage = { + content: this.audioInput, + options: { + messageType: 'voice', + }, }; - - const response = await this.amplifyService.interactions().send(this.botName, interactionsMessage); + + const response = await this.amplifyService + .interactions() + .send(this.botName, interactionsMessage); this.lexResponse = response; this.currentVoiceState = STATES.SPEAKING.MESSAGE; @@ -263,13 +278,13 @@ export class ChatbotComponentCore implements OnInit { this.micButtonDisabled = true; const message = { - 'me': this.lexResponse.inputTranscript, - 'meSentTime': new Date().toLocaleTimeString(), - 'bot': '', - 'botSentTime': '' + me: this.lexResponse.inputTranscript, + meSentTime: new Date().toLocaleTimeString(), + bot: '', + botSentTime: '', }; - this.inputText = ""; + this.inputText = ''; message.bot = this.lexResponse.message; message.botSentTime = new Date().toLocaleTimeString(); this.messages.push(message); @@ -283,10 +298,12 @@ export class ChatbotComponentCore implements OnInit { } if (this.lexResponse.contentType === 'audio/mpeg') { this.audioControl.play(this.lexResponse.audioStream, () => { - if (this.lexResponse.dialogState === 'ReadyForFulfillment' || + if ( + this.lexResponse.dialogState === 'ReadyForFulfillment' || this.lexResponse.dialogState === 'Fulfilled' || this.lexResponse.dialogState === 'Failed' || - !this.conversationModeOn) { + !this.conversationModeOn + ) { this.inputDisabled = false; this.currentVoiceState = STATES.INITIAL.MESSAGE; this.micText = STATES.INITIAL.ICON; diff --git a/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.component.ionic.ts b/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.component.ionic.ts index 8b247126b85..f580ee150b0 100644 --- a/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.component.ionic.ts @@ -105,18 +105,17 @@ const template = ` `; @Component({ - selector: 'amplify-interactions-ionic', - template + selector: 'amplify-interactions-ionic', + template, }) export class ChatbotComponentIonic extends ChatbotComponentCore { - inputValue; - - constructor( - ref: ChangeDetectorRef, - @Inject(AmplifyService) - protected amplifyService: AmplifyService) { - super(ref, amplifyService); - } + constructor( + ref: ChangeDetectorRef, + @Inject(AmplifyService) + protected amplifyService: AmplifyService + ) { + super(ref, amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.factory.ts b/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.factory.ts index 90ba4b00bb2..57bd9229de1 100644 --- a/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.factory.ts +++ b/packages/aws-amplify-angular/src/components/interactions/chatbot/chatbot.factory.ts @@ -14,77 +14,79 @@ // tslint:enable import { - Component, - Input, - OnInit, - ViewChild, - ComponentFactoryResolver, - OnDestroy, - Output, - EventEmitter + Component, + Input, + OnInit, + ViewChild, + ComponentFactoryResolver, + OnDestroy, + Output, + EventEmitter, } from '@angular/core'; import { DynamicComponentDirective } from '../../../directives/dynamic.component.directive'; -import { ComponentMount } from '../../component.mount'; +import { ComponentMount } from '../../component.mount'; import { ChatBotClass } from './chatbot.class'; import { ChatbotComponentIonic } from './chatbot.component.ionic'; import { ChatbotComponentCore } from './chatbot.component.core'; @Component({ - selector: 'amplify-interactions', - template: ` -
- -
- ` + selector: 'amplify-interactions', + template: ` +
+ +
+ `, }) export class ChatBotComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() bot: string; - @Input() title: string; - @Input() clearComplete: boolean; - @Input() conversationModeOn: boolean; - @Input() voiceConfig: any; - @Input() voiceEnabled: boolean; - @Input() textEnabled: boolean; - @Output() + @Input() framework: string; + @Input() bot: string; + @Input() title: string; + @Input() clearComplete: boolean; + @Input() conversationModeOn: boolean; + @Input() voiceConfig: any; + @Input() voiceEnabled: boolean; + @Input() textEnabled: boolean; + @Output() complete: EventEmitter = new EventEmitter(); - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnInit() { - this.loadComponent(); - } + ngOnInit() { + this.loadComponent(); + } - ngOnDestroy() {} + ngOnDestroy() {} - loadComponent() { + loadComponent() { + const interactionParams = { + bot: this.bot, + title: this.title, + clearComplete: this.clearComplete, + conversationModeOn: this.conversationModeOn, + voiceConfig: this.voiceConfig, + voiceEnabled: this.voiceEnabled, + textEnabled: this.textEnabled, + }; - const interactionParams = { - bot: this.bot, - title: this.title, - clearComplete: this.clearComplete, - conversationModeOn: this.conversationModeOn, - voiceConfig: this.voiceConfig, - voiceEnabled: this.voiceEnabled, - textEnabled: this.textEnabled - }; + const interactionComponent = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(ChatbotComponentIonic, interactionParams) + : new ComponentMount(ChatbotComponentCore, interactionParams); - const interactionComponent = this.framework && this.framework.toLowerCase() === 'ionic' ? - new ComponentMount(ChatbotComponentIonic, interactionParams) : - new ComponentMount(ChatbotComponentCore, interactionParams); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + interactionComponent.component + ); - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(interactionComponent.component); + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = interactionComponent.data; - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = interactionComponent.data; - - componentRef.instance.complete.subscribe((e) => { - this.complete.emit(e); - }); - } + componentRef.instance.complete.subscribe(e => { + this.complete.emit(e); + }); + } } diff --git a/packages/aws-amplify-angular/src/components/interactions/chatbot/index.ts b/packages/aws-amplify-angular/src/components/interactions/chatbot/index.ts index cf5425a2dc9..014476b4fc0 100644 --- a/packages/aws-amplify-angular/src/components/interactions/chatbot/index.ts +++ b/packages/aws-amplify-angular/src/components/interactions/chatbot/index.ts @@ -13,7 +13,7 @@ */ // tslint:enable -export { ChatBotComponent } from './chatbot.factory'; +export { ChatBotComponent } from './chatbot.factory'; export { ChatBotClass } from './chatbot.class'; export { ChatbotComponentCore } from './chatbot.component.core'; export { ChatbotComponentIonic } from './chatbot.component.ionic'; diff --git a/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.class.ts b/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.class.ts index ab1dbe20a61..0a257f65ff5 100644 --- a/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.class.ts +++ b/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.class.ts @@ -14,5 +14,5 @@ // tslint:enable export class PhotoPickerClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.component.core.ts b/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.component.core.ts index 42b9a7e7139..fdb753a2bc5 100644 --- a/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.component.core.ts +++ b/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.component.core.ts @@ -13,7 +13,14 @@ */ // tslint:enable -import { Component, Input, Output, EventEmitter, OnInit, Inject } from '@angular/core'; +import { + Component, + Input, + Output, + EventEmitter, + OnInit, + Inject, +} from '@angular/core'; import { AmplifyService } from '../../../providers/amplify.service'; const template = ` @@ -52,122 +59,131 @@ const template = ` `; @Component({ - selector: 'amplify-photo-picker-core', - template + selector: 'amplify-photo-picker-core', + template, }) export class PhotoPickerComponentCore implements OnInit { - photoUrl: string; - hasPhoto: boolean = false; - uploading: boolean = false; - s3ImageFile: any = null; - s3ImagePath: string = ""; - _storageOptions: any = {}; - errorMessage: string; - protected logger: any; - - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - this.logger = this.amplifyService.logger('PhotoPickerComponent'); - } - - @Input() - set url(url: string) { - this.photoUrl = url; - this.hasPhoto = true; - } - - @Input() - set storageOptions(storageOptions: any){ - this._storageOptions = Object.assign(this._storageOptions, storageOptions); - } - - @Input() - set path(path: string){ - this.s3ImagePath = path; - } - - @Input() - set data(data: any) { - this.photoUrl = data.url; - this.s3ImagePath = data.path; - this._storageOptions = Object.assign(this._storageOptions, data.storageOptions); - this.hasPhoto = true; - } - - @Output() - picked: EventEmitter = new EventEmitter(); - - @Output() - loaded: EventEmitter = new EventEmitter(); - - @Output() - uploaded: EventEmitter = new EventEmitter(); - - ngOnInit() { - if (!this.amplifyService.storage()){ - throw new Error('Storage module not registered on AmplifyService provider'); - } - } - - pick(evt) { - const file = evt.target.files[0]; - if (!file) { return; } - if (!this._storageOptions.contentType) { - this._storageOptions.contentType = file.type; - } - const { name, size, type } = file; - this.picked.emit(file); - - this.s3ImagePath = `${this.s3ImagePath}/${file.name}`; - this.s3ImageFile = file; - const that = this; - const reader = new FileReader(); - reader.onload = function(e) { - const target: any = e.target; - const url = target.result; - that.photoUrl = url; - that.hasPhoto = true; - that.loaded.emit(url); - }; - reader.readAsDataURL(file); - } - - uploadFile() { - this.uploading = true; - this.amplifyService.storage().put( - this.s3ImagePath, - this.s3ImageFile, this._storageOptions) - .then ( result => { - this.uploaded.emit(result); - this.completeFileUpload(); - }) - .catch( error => { - this.completeFileUpload(error); - }); - } - - completeFileUpload(error?:any) { - if (error) { - return this._setError(error); - } - this.s3ImagePath = ""; - this.photoUrl = null; - this.s3ImageFile = null; - this.uploading = false; - } - - onPhotoError() { - this.hasPhoto = false; - } - - onAlertClose() { - this._setError(null); - } - - _setError(err) { - if (!err) { - this.errorMessage = null; - return; - } - this.errorMessage = err.message || err; - } + photoUrl: string; + hasPhoto: boolean = false; + uploading: boolean = false; + s3ImageFile: any = null; + s3ImagePath: string = ''; + _storageOptions: any = {}; + errorMessage: string; + protected logger: any; + + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + this.logger = this.amplifyService.logger('PhotoPickerComponent'); + } + + @Input() + set url(url: string) { + this.photoUrl = url; + this.hasPhoto = true; + } + + @Input() + set storageOptions(storageOptions: any) { + this._storageOptions = Object.assign(this._storageOptions, storageOptions); + } + + @Input() + set path(path: string) { + this.s3ImagePath = path; + } + + @Input() + set data(data: any) { + this.photoUrl = data.url; + this.s3ImagePath = data.path; + this._storageOptions = Object.assign( + this._storageOptions, + data.storageOptions + ); + this.hasPhoto = true; + } + + @Output() + picked: EventEmitter = new EventEmitter(); + + @Output() + loaded: EventEmitter = new EventEmitter(); + + @Output() + uploaded: EventEmitter = new EventEmitter(); + + ngOnInit() { + if (!this.amplifyService.storage()) { + throw new Error( + 'Storage module not registered on AmplifyService provider' + ); + } + } + + pick(evt) { + const file = evt.target.files[0]; + if (!file) { + return; + } + if (!this._storageOptions.contentType) { + this._storageOptions.contentType = file.type; + } + const { name, size, type } = file; + this.picked.emit(file); + + this.s3ImagePath = `${this.s3ImagePath}/${file.name}`; + this.s3ImageFile = file; + const that = this; + const reader = new FileReader(); + reader.onload = function(e) { + const target: any = e.target; + const url = target.result; + that.photoUrl = url; + that.hasPhoto = true; + that.loaded.emit(url); + }; + reader.readAsDataURL(file); + } + + uploadFile() { + this.uploading = true; + this.amplifyService + .storage() + .put(this.s3ImagePath, this.s3ImageFile, this._storageOptions) + .then(result => { + this.uploaded.emit(result); + this.completeFileUpload(); + }) + .catch(error => { + this.completeFileUpload(error); + }); + } + + completeFileUpload(error?: any) { + if (error) { + return this._setError(error); + } + this.s3ImagePath = ''; + this.photoUrl = null; + this.s3ImageFile = null; + this.uploading = false; + } + + onPhotoError() { + this.hasPhoto = false; + } + + onAlertClose() { + this._setError(null); + } + + _setError(err) { + if (!err) { + this.errorMessage = null; + return; + } + this.errorMessage = err.message || err; + } } diff --git a/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.component.ionic.ts b/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.component.ionic.ts index 700455cecc5..c1d34f6c2b5 100644 --- a/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.component.ionic.ts @@ -1,4 +1,3 @@ - // tslint:disable /* * Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -18,7 +17,6 @@ import { Component, Inject } from '@angular/core'; import { AmplifyService } from '../../../providers/amplify.service'; import { PhotoPickerComponentCore } from './photo-picker.component.core'; - const template = `
@@ -55,13 +53,13 @@ const template = ` `; @Component({ - selector: 'amplify-photo-picker-ionic', - template + selector: 'amplify-photo-picker-ionic', + template, }) export class PhotoPickerIonicComponent extends PhotoPickerComponentCore { - - constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) { - super(amplifyService); - - } + constructor( + @Inject(AmplifyService) protected amplifyService: AmplifyService + ) { + super(amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.factory.ts b/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.factory.ts index 3fae86ec526..26bd9f2d5a7 100644 --- a/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.factory.ts +++ b/packages/aws-amplify-angular/src/components/storage/photo-picker-component/photo-picker.factory.ts @@ -1,4 +1,3 @@ - // tslint:disable /* * Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -14,88 +13,86 @@ */ // tslint:enable -import { - Component, - Input, - OnInit, - ViewChild, - ComponentFactoryResolver, - OnDestroy, - Output, - EventEmitter +import { + Component, + Input, + OnInit, + ViewChild, + ComponentFactoryResolver, + OnDestroy, + Output, + EventEmitter, } from '@angular/core'; import { DynamicComponentDirective } from '../../../directives/dynamic.component.directive'; -import { ComponentMount } from '../../component.mount'; +import { ComponentMount } from '../../component.mount'; import { PhotoPickerClass } from './photo-picker.class'; import { PhotoPickerIonicComponent } from './photo-picker.component.ionic'; import { PhotoPickerComponentCore } from './photo-picker.component.core'; @Component({ - selector: 'amplify-photo-picker', - template: ` -
- -
- ` + selector: 'amplify-photo-picker', + template: ` +
+ +
+ `, }) export class PhotoPickerComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() url: string; - @Input() path: string; - @Input() storageOptions: any; - @Output() - picked: EventEmitter = new EventEmitter(); - @Output() - loaded: EventEmitter = new EventEmitter(); - @Output() - uploaded: EventEmitter = new EventEmitter(); - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; - - constructor(private componentFactoryResolver: ComponentFactoryResolver) { - - } - - ngOnInit() { - this.loadComponent(); - } - - ngOnDestroy() {} - - - loadComponent() { - - const photoPickerComponent = this.framework && this.framework.toLowerCase() === 'ionic' ? - new ComponentMount(PhotoPickerIonicComponent, { - url: this.url, - path: this.path, - storageOptions: this.storageOptions - }) : - new ComponentMount(PhotoPickerComponentCore, { - url: this.url, - path: this.path, - storageOptions: this.storageOptions - }); - - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(photoPickerComponent.component); - - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); - - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = photoPickerComponent.data; - - componentRef.instance.picked.subscribe((e) => { - this.picked.emit(e); - }); - - componentRef.instance.loaded.subscribe((e) => { - this.loaded.emit(e); - }); - - componentRef.instance.uploaded.subscribe((e) => { - this.uploaded.emit(e); - }); - - } + @Input() framework: string; + @Input() url: string; + @Input() path: string; + @Input() storageOptions: any; + @Output() + picked: EventEmitter = new EventEmitter(); + @Output() + loaded: EventEmitter = new EventEmitter(); + @Output() + uploaded: EventEmitter = new EventEmitter(); + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; + + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} + + ngOnInit() { + this.loadComponent(); + } + + ngOnDestroy() {} + + loadComponent() { + const photoPickerComponent = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(PhotoPickerIonicComponent, { + url: this.url, + path: this.path, + storageOptions: this.storageOptions, + }) + : new ComponentMount(PhotoPickerComponentCore, { + url: this.url, + path: this.path, + storageOptions: this.storageOptions, + }); + + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + photoPickerComponent.component + ); + + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); + + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = photoPickerComponent.data; + + componentRef.instance.picked.subscribe(e => { + this.picked.emit(e); + }); + + componentRef.instance.loaded.subscribe(e => { + this.loaded.emit(e); + }); + + componentRef.instance.uploaded.subscribe(e => { + this.uploaded.emit(e); + }); + } } diff --git a/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.class.ts b/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.class.ts index 8d0d1f4c118..00c46b3ce1f 100644 --- a/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.class.ts +++ b/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.class.ts @@ -14,5 +14,5 @@ // tslint:enable export class S3AlbumClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.component.core.ts b/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.component.core.ts index 3705678a042..38e9efcc825 100644 --- a/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.component.core.ts +++ b/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.component.core.ts @@ -31,56 +31,63 @@ const template = ` `; @Component({ - selector: 'amplify-s3-album-core', - template + selector: 'amplify-s3-album-core', + template, }) export class S3AlbumComponentCore implements OnInit { - list: Array; - _path: string; - _options: any = {}; - protected logger: any; + list: Array; + _path: string; + _options: any = {}; + protected logger: any; - @Output() - selected: EventEmitter = new EventEmitter(); + @Output() + selected: EventEmitter = new EventEmitter(); - constructor(protected amplifyService: AmplifyService) { - this.logger = this.amplifyService.logger('S3AlbumComponent'); - } + constructor(protected amplifyService: AmplifyService) { + this.logger = this.amplifyService.logger('S3AlbumComponent'); + } - ngOnInit() { - if (!this.amplifyService.storage()){ - throw new Error('Storage module not registered on AmplifyService provider'); - } - this.getList(this._path, this._options); - } + ngOnInit() { + if (!this.amplifyService.storage()) { + throw new Error( + 'Storage module not registered on AmplifyService provider' + ); + } + this.getList(this._path, this._options); + } - onImageSelected(event) { - this.selected.emit(event); - } + onImageSelected(event) { + this.selected.emit(event); + } - @Input() set data(data: any){ - if (!data.path) { return; } - this._path = data.path; - this._options = data.options; - } + @Input() set data(data: any) { + if (!data.path) { + return; + } + this._path = data.path; + this._options = data.options; + } - @Input() set path(path: string) { - this._path = path; - } + @Input() set path(path: string) { + this._path = path; + } - @Input() set options(options: any) { - this._options = options; - } + @Input() set options(options: any) { + this._options = options; + } - getList(path, options) { - if (!path) {return; } - this.amplifyService.storage() - .list(path, options) - .then(data => { - this.list = data.map(item => { - return { path: item.key }; - }); - }) - .catch(e => console.error(e)); - } + getList(path, options) { + if (!path) { + return; + } + this.amplifyService + .storage() + .list(path, options) + .then(data => { + this.list = data.map(item => { + return { path: item.key }; + }); + }) + .catch(e => console.error(e)); + } } diff --git a/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.component.ionic.ts b/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.component.ionic.ts index 7c53393711d..476b467cf51 100644 --- a/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/storage/s3-album-component/s3-album.component.ionic.ts @@ -13,11 +13,17 @@ */ // tslint:enable -import { Component, Input, ViewEncapsulation, Injector, ElementRef } from '@angular/core'; +import { + Component, + Input, + ViewEncapsulation, + Injector, + ElementRef, +} from '@angular/core'; import { AmplifyService } from '../../../providers/amplify.service'; import { S3AlbumComponentCore } from './s3-album.component.core'; -const template = ` +const template = `
- -
- ` + selector: 'amplify-s3-album', + template: ` +
+ +
+ `, }) export class S3AlbumComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() path: string; - @Input() options: any; - @Output() - selected: EventEmitter = new EventEmitter(); - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; + @Input() framework: string; + @Input() path: string; + @Input() options: any; + @Output() + selected: EventEmitter = new EventEmitter(); + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnInit() { - this.loadComponent(); - } + ngOnInit() { + this.loadComponent(); + } - ngOnDestroy() {} + ngOnDestroy() {} - loadComponent() { + loadComponent() { + const albumComponent = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(S3AlbumComponentIonic, { + path: this.path, + options: this.options, + }) + : new ComponentMount(S3AlbumComponentCore, { + path: this.path, + options: this.options, + }); - const albumComponent = this.framework && this.framework.toLowerCase() === 'ionic' ? - new ComponentMount(S3AlbumComponentIonic,{path: this.path, options: this.options}) : - new ComponentMount(S3AlbumComponentCore, {path: this.path, options: this.options}); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + albumComponent.component + ); - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(albumComponent.component); + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = albumComponent.data; - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = albumComponent.data; - - componentRef.instance.selected.subscribe((e) => { - this.selected.emit(e); - }); - - } + componentRef.instance.selected.subscribe(e => { + this.selected.emit(e); + }); + } } diff --git a/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.class.ts b/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.class.ts index 41fb5c97ee2..fab8142cf10 100644 --- a/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.class.ts +++ b/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.class.ts @@ -14,5 +14,5 @@ // tslint:enable export class S3ImageClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.component.core.ts b/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.component.core.ts index ce2b03d637a..28a6250bc5d 100644 --- a/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.component.core.ts +++ b/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.component.core.ts @@ -25,55 +25,62 @@ const template = ` `; @Component({ - selector: 'amplify-s3-image-core', - template + selector: 'amplify-s3-image-core', + template, }) export class S3ImageComponentCore implements OnInit { - url: any; - _path: string; - _options: any = {}; - protected logger: any; + url: any; + _path: string; + _options: any = {}; + protected logger: any; - @Output() - selected: EventEmitter = new EventEmitter(); + @Output() + selected: EventEmitter = new EventEmitter(); - constructor(protected amplifyService: AmplifyService) { - this.logger = this.amplifyService.logger('S3ImageComponent'); - } + constructor(protected amplifyService: AmplifyService) { + this.logger = this.amplifyService.logger('S3ImageComponent'); + } - @Input() - set data(data:any){ - if (!data.path) { return; } - this._path = data.path; - this._options = data.options; - } + @Input() + set data(data: any) { + if (!data.path) { + return; + } + this._path = data.path; + this._options = data.options; + } - @Input() - set path(path: string) { - this._path = path; - } + @Input() + set path(path: string) { + this._path = path; + } - @Input() - set options(options: any) { - this._options = options; - } + @Input() + set options(options: any) { + this._options = options; + } - ngOnInit() { - if (!this._path) { return; } - if (!this.amplifyService.storage()){ - throw new Error('Storage module not registered on AmplifyService provider'); - } - this.getImage(this._path, this._options); - } + ngOnInit() { + if (!this._path) { + return; + } + if (!this.amplifyService.storage()) { + throw new Error( + 'Storage module not registered on AmplifyService provider' + ); + } + this.getImage(this._path, this._options); + } - onImageClicked() { - this.selected.emit(this.url); - } + onImageClicked() { + this.selected.emit(this.url); + } - getImage(path, options) { - this.amplifyService.storage() - .get(path, options) - .then(url => this.url = url) - .catch(e => console.error(e)); - } + getImage(path, options) { + this.amplifyService + .storage() + .get(path, options) + .then(url => (this.url = url)) + .catch(e => console.error(e)); + } } diff --git a/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.component.ionic.ts b/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.component.ionic.ts index 707da915a7a..351e9033b76 100644 --- a/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.component.ionic.ts @@ -13,7 +13,13 @@ */ // tslint:enable -import { Component, Input, ViewEncapsulation, Injector, ElementRef } from '@angular/core'; +import { + Component, + Input, + ViewEncapsulation, + Injector, + ElementRef, +} from '@angular/core'; import { AmplifyService } from '../../../providers/amplify.service'; import { S3ImageComponentCore } from './s3-image.component.core'; @@ -26,13 +32,11 @@ const template = ` `; @Component({ - selector: 'amplify-s3-image-ionic', - template + selector: 'amplify-s3-image-ionic', + template, }) export class S3ImageComponentIonic extends S3ImageComponentCore { - - constructor(protected amplifyService: AmplifyService) { - super(amplifyService); - - } + constructor(protected amplifyService: AmplifyService) { + super(amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.factory.ts b/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.factory.ts index 2346e9921c6..b23270d0ab5 100644 --- a/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.factory.ts +++ b/packages/aws-amplify-angular/src/components/storage/s3-image-component/s3-image.factory.ts @@ -14,62 +14,70 @@ // tslint:enable import { - Component, - Input, - OnInit, - ViewChild, - ComponentFactoryResolver, - OnDestroy, - Output, - EventEmitter + Component, + Input, + OnInit, + ViewChild, + ComponentFactoryResolver, + OnDestroy, + Output, + EventEmitter, } from '@angular/core'; import { DynamicComponentDirective } from '../../../directives/dynamic.component.directive'; -import { ComponentMount } from '../../component.mount'; +import { ComponentMount } from '../../component.mount'; import { S3ImageClass } from './s3-image.class'; import { S3ImageComponentIonic } from './s3-image.component.ionic'; import { S3ImageComponentCore } from './s3-image.component.core'; @Component({ - selector: 'amplify-s3-image', - template: ` -
- -
- ` + selector: 'amplify-s3-image', + template: ` +
+ +
+ `, }) export class S3ImageComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() path: string; - @Input() options: any; - @Output() - selected: EventEmitter = new EventEmitter(); - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; + @Input() framework: string; + @Input() path: string; + @Input() options: any; + @Output() + selected: EventEmitter = new EventEmitter(); + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnInit() { - this.loadComponent(); - } + ngOnInit() { + this.loadComponent(); + } - ngOnDestroy() {} + ngOnDestroy() {} - loadComponent() { + loadComponent() { + const imageComponent = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(S3ImageComponentIonic, { + path: this.path, + options: this.options, + }) + : new ComponentMount(S3ImageComponentCore, { + path: this.path, + options: this.options, + }); - const imageComponent = this.framework && this.framework.toLowerCase() === 'ionic' ? - new ComponentMount(S3ImageComponentIonic,{path:this.path, options: this.options}) : - new ComponentMount(S3ImageComponentCore, {path: this.path, options: this.options}); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory( + imageComponent.component + ); - const componentFactory = this.componentFactoryResolver - .resolveComponentFactory(imageComponent.component); + const viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - const viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = imageComponent.data; - const componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = imageComponent.data; - - componentRef.instance.selected.subscribe((e) => { - this.selected.emit(e); - }); - } + componentRef.instance.selected.subscribe(e => { + this.selected.emit(e); + }); + } } diff --git a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/index.ts b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/index.ts index 1307a48c5fd..9346a98dead 100644 --- a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/index.ts +++ b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/index.ts @@ -11,4 +11,4 @@ * and limitations under the License. */ export { SumerianSceneComponentCore } from './sumerian-scene.component.core'; -export { SumerianSceneComponentIonic } from './sumerian-scene.component.ionic'; \ No newline at end of file +export { SumerianSceneComponentIonic } from './sumerian-scene.component.ionic'; diff --git a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene-loading.component.core.ts b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene-loading.component.core.ts index 84beb6bff00..fd5e94cdb8e 100644 --- a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene-loading.component.core.ts +++ b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene-loading.component.core.ts @@ -82,17 +82,17 @@ const template = ` `; @Component({ - selector: 'sumerian-scene-loading-core', - template + selector: 'sumerian-scene-loading-core', + template, }) export class SumerianSceneLoadingComponentCore { - @Input() loadPercentage: number; - @Input() sceneName: string; - @Input() sceneError: string | null; + @Input() loadPercentage: number; + @Input() sceneName: string; + @Input() sceneError: string | null; - AmplifyUI: any; + AmplifyUI: any; - constructor() { - this.AmplifyUI = AmplifyUI; - } + constructor() { + this.AmplifyUI = AmplifyUI; + } } diff --git a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene-loading.component.ionic.ts b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene-loading.component.ionic.ts index b534329d47d..f9a9050e238 100644 --- a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene-loading.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene-loading.component.ionic.ts @@ -82,11 +82,11 @@ const template = ` `; @Component({ - selector: 'sumerian-scene-loading-ionic', - template + selector: 'sumerian-scene-loading-ionic', + template, }) export class SumerianSceneLoadingComponentIonic extends SumerianSceneLoadingComponentCore { - constructor() { - super(); - } + constructor() { + super(); + } } diff --git a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.class.ts b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.class.ts index 405223d66dd..a75dfc767cd 100644 --- a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.class.ts +++ b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.class.ts @@ -11,5 +11,5 @@ * and limitations under the License. */ export class SumerianSceneClass { - data: any; + data: any; } diff --git a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.component.core.ts b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.component.core.ts index 60526233f8f..6e81894d529 100644 --- a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.component.core.ts +++ b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.component.core.ts @@ -84,129 +84,170 @@ const template = ` `; @Component({ - selector: 'sumerian-scene-core', - template + selector: 'sumerian-scene-core', + template, }) export class SumerianSceneComponentCore implements OnInit, OnDestroy { - @Input() sceneName: string; - - loading = false; - loadPercentage = 0; - muted = false; - showEnableAudio = false; - isVRCapable = false; - isVRPresentationActive = false; - isFullscreen = false; - sceneError = null; - amplifyUI: any; - protected logger: any; - - @Input() - set data(data: any) { - this.sceneName = data.sceneName; - } - - constructor(protected amplifyService: AmplifyService) { - this.amplifyUI = AmplifyUI; - this.logger = this.amplifyService.logger('SumerianSceneComponentCore'); - } - - ngOnInit() { - document.addEventListener('fullscreenchange', this.onFullscreenChange.bind(this)); - document.addEventListener('webkitfullscreenchange', this.onFullscreenChange.bind(this)); - document.addEventListener('mozfullscreenchange', this.onFullscreenChange.bind(this)); - document.addEventListener('MSFullscreenChange', this.onFullscreenChange.bind(this)); - - if (!this.amplifyService.xr()){ - throw new Error('XR module not registered on AmplifyService provider'); - } - - this.loadAndStartScene(); - - - } - - ngOnDestroy() { - document.removeEventListener('fullscreenchange', this.onFullscreenChange.bind(this)); - document.removeEventListener('webkitfullscreenchange', this.onFullscreenChange.bind(this)); - document.removeEventListener('mozfullscreenchange', this.onFullscreenChange.bind(this)); - document.removeEventListener('MSFullscreenChange', this.onFullscreenChange.bind(this)); - } - - progressCallback = (progress) => { - const percentage = progress * 100; - this.loadPercentage = percentage; - } - - async loadAndStartScene() { - this.loading = true; - const sceneOptions = { - progressCallback: this.progressCallback - }; - try { - await this.amplifyService.xr() - .loadScene(this.sceneName, "sumerian-scene-dom-id", sceneOptions); - } catch (e) { - this.sceneError = 'Failed to load scene'; - this.logger.error(this.sceneError, e); - return; - } - this.amplifyService.xr().start(this.sceneName); - - this.loading = false; - this.muted = this.amplifyService.xr().isMuted(this.sceneName); - - this.isVRCapable = this.amplifyService.xr().isVRCapable(this.sceneName); - this.isVRPresentationActive = this.amplifyService.xr().isVRPresentationActive(this.sceneName); - - this.amplifyService.xr() - .onSceneEvent(this.sceneName, 'AudioEnabled', () => this.showEnableAudio = false); - this.amplifyService.xr() - .onSceneEvent(this.sceneName, 'AudioDisabled', () => this.showEnableAudio = true); - } - - setMuted(muted) { - this.muted = muted; - this.amplifyService.xr().setMuted(this.sceneName, muted); - if (this.showEnableAudio) { - this.amplifyService.xr().enableAudio(this.sceneName); - this.showEnableAudio = false; - } - } - - toggleVRPresentation() { - try { - if (this.isVRPresentationActive) { - this.amplifyService.xr().exitVR(this.sceneName); - } else { - this.amplifyService.xr().enterVR(this.sceneName); - } - } catch(e) { - this.logger.error('Unable to start/stop WebVR System: ' + e.message); - return; - } - this.isVRPresentationActive = !this.isVRPresentationActive; - } - - onFullscreenChange() { - const doc: any = document; - this.isFullscreen = doc.fullscreenElement !== null; - } - - async maximize() { - const sceneDomElement: any = document.getElementById("sumerian-scene-container"); - const requestFullScreen = sceneDomElement.requestFullscreen || sceneDomElement.msRequestFullscreen || sceneDomElement.mozRequestFullScreen || sceneDomElement.webkitRequestFullscreen; - requestFullScreen.call(sceneDomElement); - } - - async minimize() { - const doc: any = document; - if(doc.exitFullscreen) { - doc.exitFullscreen(); - } else if(doc.mozCancelFullScreen) { - doc.mozCancelFullScreen(); - } else if(doc.webkitExitFullscreen) { - doc.webkitExitFullscreen(); - } - } + @Input() sceneName: string; + + loading = false; + loadPercentage = 0; + muted = false; + showEnableAudio = false; + isVRCapable = false; + isVRPresentationActive = false; + isFullscreen = false; + sceneError = null; + amplifyUI: any; + protected logger: any; + + @Input() + set data(data: any) { + this.sceneName = data.sceneName; + } + + constructor(protected amplifyService: AmplifyService) { + this.amplifyUI = AmplifyUI; + this.logger = this.amplifyService.logger('SumerianSceneComponentCore'); + } + + ngOnInit() { + document.addEventListener( + 'fullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.addEventListener( + 'webkitfullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.addEventListener( + 'mozfullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.addEventListener( + 'MSFullscreenChange', + this.onFullscreenChange.bind(this) + ); + + if (!this.amplifyService.xr()) { + throw new Error('XR module not registered on AmplifyService provider'); + } + + this.loadAndStartScene(); + } + + ngOnDestroy() { + document.removeEventListener( + 'fullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.removeEventListener( + 'webkitfullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.removeEventListener( + 'mozfullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.removeEventListener( + 'MSFullscreenChange', + this.onFullscreenChange.bind(this) + ); + } + + progressCallback = progress => { + const percentage = progress * 100; + this.loadPercentage = percentage; + }; + + async loadAndStartScene() { + this.loading = true; + const sceneOptions = { + progressCallback: this.progressCallback, + }; + try { + await this.amplifyService + .xr() + .loadScene(this.sceneName, 'sumerian-scene-dom-id', sceneOptions); + } catch (e) { + this.sceneError = 'Failed to load scene'; + this.logger.error(this.sceneError, e); + return; + } + this.amplifyService.xr().start(this.sceneName); + + this.loading = false; + this.muted = this.amplifyService.xr().isMuted(this.sceneName); + + this.isVRCapable = this.amplifyService.xr().isVRCapable(this.sceneName); + this.isVRPresentationActive = this.amplifyService + .xr() + .isVRPresentationActive(this.sceneName); + + this.amplifyService + .xr() + .onSceneEvent( + this.sceneName, + 'AudioEnabled', + () => (this.showEnableAudio = false) + ); + this.amplifyService + .xr() + .onSceneEvent( + this.sceneName, + 'AudioDisabled', + () => (this.showEnableAudio = true) + ); + } + + setMuted(muted) { + this.muted = muted; + this.amplifyService.xr().setMuted(this.sceneName, muted); + if (this.showEnableAudio) { + this.amplifyService.xr().enableAudio(this.sceneName); + this.showEnableAudio = false; + } + } + + toggleVRPresentation() { + try { + if (this.isVRPresentationActive) { + this.amplifyService.xr().exitVR(this.sceneName); + } else { + this.amplifyService.xr().enterVR(this.sceneName); + } + } catch (e) { + this.logger.error('Unable to start/stop WebVR System: ' + e.message); + return; + } + this.isVRPresentationActive = !this.isVRPresentationActive; + } + + onFullscreenChange() { + const doc: any = document; + this.isFullscreen = doc.fullscreenElement !== null; + } + + async maximize() { + const sceneDomElement: any = document.getElementById( + 'sumerian-scene-container' + ); + const requestFullScreen = + sceneDomElement.requestFullscreen || + sceneDomElement.msRequestFullscreen || + sceneDomElement.mozRequestFullScreen || + sceneDomElement.webkitRequestFullscreen; + requestFullScreen.call(sceneDomElement); + } + + async minimize() { + const doc: any = document; + if (doc.exitFullscreen) { + doc.exitFullscreen(); + } else if (doc.mozCancelFullScreen) { + doc.mozCancelFullScreen(); + } else if (doc.webkitExitFullscreen) { + doc.webkitExitFullscreen(); + } + } } diff --git a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.component.ionic.ts b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.component.ionic.ts index 2f40a5937a3..ed61b4e1334 100644 --- a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.component.ionic.ts +++ b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.component.ionic.ts @@ -84,13 +84,13 @@ const template = ` `; @Component({ - selector: 'sumerian-scene-ionic', - template + selector: 'sumerian-scene-ionic', + template, }) export class SumerianSceneComponentIonic extends SumerianSceneComponentCore { - amplifyUI: any; + amplifyUI: any; - constructor(protected amplifyService: AmplifyService) { - super(amplifyService); - } + constructor(protected amplifyService: AmplifyService) { + super(amplifyService); + } } diff --git a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.factory.ts b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.factory.ts index aac24cebe10..73df4b2c897 100644 --- a/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.factory.ts +++ b/packages/aws-amplify-angular/src/components/xr/sumerian-scene-component/sumerian-scene.factory.ts @@ -10,43 +10,59 @@ * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ -import { Component, Input, OnInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '@angular/core'; +import { + Component, + Input, + OnInit, + ViewChild, + ComponentFactoryResolver, + OnDestroy, +} from '@angular/core'; import { DynamicComponentDirective } from '../../../directives/dynamic.component.directive'; -import { ComponentMount } from '../../component.mount'; +import { ComponentMount } from '../../component.mount'; import { SumerianSceneClass } from './sumerian-scene.class'; import { SumerianSceneComponentCore } from './sumerian-scene.component.core'; -import { SumerianSceneComponentIonic } from './sumerian-scene.component.ionic' +import { SumerianSceneComponentIonic } from './sumerian-scene.component.ionic'; @Component({ - selector: 'amplify-sumerian-scene', - template: ` - - ` + selector: 'amplify-sumerian-scene', + template: ` + + `, }) export class SumerianSceneComponent implements OnInit, OnDestroy { - @Input() framework: string; - @Input() sceneName: string; - @ViewChild(DynamicComponentDirective) componentHost: DynamicComponentDirective; + @Input() framework: string; + @Input() sceneName: string; + @ViewChild(DynamicComponentDirective) + componentHost: DynamicComponentDirective; - constructor(private componentFactoryResolver: ComponentFactoryResolver) { } + constructor(private componentFactoryResolver: ComponentFactoryResolver) {} - ngOnInit() { - this.loadComponent(); - } + ngOnInit() { + this.loadComponent(); + } - ngOnDestroy() {} + ngOnDestroy() {} - loadComponent() { + loadComponent() { + let sumerianScene = + this.framework && this.framework.toLowerCase() === 'ionic' + ? new ComponentMount(SumerianSceneComponentIonic, { + sceneName: this.sceneName, + }) + : new ComponentMount(SumerianSceneComponentCore, { + sceneName: this.sceneName, + }); - let sumerianScene = this.framework && this.framework.toLowerCase() === 'ionic' ? new ComponentMount(SumerianSceneComponentIonic,{sceneName: this.sceneName}) : new ComponentMount(SumerianSceneComponentCore, {sceneName: this.sceneName}); + let componentFactory = this.componentFactoryResolver.resolveComponentFactory( + sumerianScene.component + ); - let componentFactory = this.componentFactoryResolver.resolveComponentFactory(sumerianScene.component); + let viewContainerRef = this.componentHost.viewContainerRef; + viewContainerRef.clear(); - let viewContainerRef = this.componentHost.viewContainerRef; - viewContainerRef.clear(); - - let componentRef = viewContainerRef.createComponent(componentFactory); - (componentRef.instance).data = sumerianScene.data; - } -} \ No newline at end of file + let componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = sumerianScene.data; + } +} diff --git a/packages/aws-amplify-angular/src/directives/dynamic.component.directive.ts b/packages/aws-amplify-angular/src/directives/dynamic.component.directive.ts index 0f36a14c55c..187e540f86f 100644 --- a/packages/aws-amplify-angular/src/directives/dynamic.component.directive.ts +++ b/packages/aws-amplify-angular/src/directives/dynamic.component.directive.ts @@ -1,8 +1,8 @@ import { Directive, ViewContainerRef } from '@angular/core'; @Directive({ - selector: '[component-host]', + selector: '[component-host]', }) export class DynamicComponentDirective { - constructor(public viewContainerRef: ViewContainerRef) { } + constructor(public viewContainerRef: ViewContainerRef) {} } diff --git a/packages/aws-amplify-angular/src/providers/amplify.compose.service.ts b/packages/aws-amplify-angular/src/providers/amplify.compose.service.ts index ffb10407790..df4ebe9270c 100644 --- a/packages/aws-amplify-angular/src/providers/amplify.compose.service.ts +++ b/packages/aws-amplify-angular/src/providers/amplify.compose.service.ts @@ -1,5 +1,5 @@ import { AmplifyService } from './amplify.service'; -export default (modules) => { - return new AmplifyService(modules); +export default modules => { + return new AmplifyService(modules); }; diff --git a/packages/aws-amplify-angular/src/providers/amplify.service.ts b/packages/aws-amplify-angular/src/providers/amplify.service.ts index 62cc4aa996f..579b61c8ffb 100644 --- a/packages/aws-amplify-angular/src/providers/amplify.service.ts +++ b/packages/aws-amplify-angular/src/providers/amplify.service.ts @@ -1,75 +1,98 @@ - // tslint:disable - /* - * Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with - * the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ - // tslint:enable +// tslint:disable +/* + * Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with + * the License. A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +// tslint:enable - import { Injectable, Optional, Inject } from '@angular/core'; - import { Subject } from 'rxjs/Subject'; - import { Observable } from 'rxjs/Observable'; - import Amplify, { Logger, I18n } from '@aws-amplify/core'; - import { AuthState } from './auth.state'; - import { authDecorator } from './auth.decorator'; - - @Injectable() - export class AmplifyService { - private _auth: any; - private _analytics: any; - private _storage: any; - private _api: any; - private _cache: any; - private _pubsub: any; - private _interactions: any; - private _logger: any; - private _xr: any; - private _i18n: any; - private _authState = new Subject(); - authStateChange$ = this._authState.asObservable(); +import { Injectable, Optional, Inject } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; +import { Observable } from 'rxjs/Observable'; +import Amplify, { Logger, I18n } from '@aws-amplify/core'; +import { AuthState } from './auth.state'; +import { authDecorator } from './auth.decorator'; +@Injectable() +export class AmplifyService { + private _auth: any; + private _analytics: any; + private _storage: any; + private _api: any; + private _cache: any; + private _pubsub: any; + private _interactions: any; + private _logger: any; + private _xr: any; + private _i18n: any; + private _authState = new Subject(); + authStateChange$ = this._authState.asObservable(); - constructor ( - @Inject('modules') - @Optional() - private modules: any = {}) { + constructor( + @Inject('modules') + @Optional() + private modules: any = {} + ) { + const source = modules || Amplify; - const source = modules || Amplify; + authDecorator(this._authState, source.Auth); - authDecorator(this._authState, source.Auth); + this._auth = source.Auth; + this._analytics = source.Analytics; + this._storage = source.Storage; + this._api = source.API; + this._cache = source.Cache; + this._pubsub = source.PubSub; + this._interactions = source.Interactions; + this._xr = source.XR; - this._auth = source.Auth; - this._analytics = source.Analytics; - this._storage = source.Storage; - this._api = source.API; - this._cache = source.Cache; - this._pubsub = source.PubSub; - this._interactions = source.Interactions; - this._xr = source.XR; + // i18n and logger instantiated by default (do not change) + this._i18n = I18n; + this._logger = Logger; + } - // i18n and logger instantiated by default (do not change) - this._i18n = I18n; - this._logger = Logger; - } + auth(): any { + return this._auth; + } + analytics(): any { + return this._analytics; + } + storage(): any { + return this._storage; + } + api(): any { + return this._api; + } + interactions(): any { + return this._interactions; + } + cache(): any { + return this._cache; + } + pubsub(): any { + return this._pubsub; + } + logger(name, level?): Logger { + return new this._logger(name, level); + } + xr(): any { + return this._xr; + } + i18n(): any { + return this._i18n; + } - auth(): any { return this._auth; } - analytics(): any { return this._analytics; } - storage(): any { return this._storage; } - api(): any { return this._api; } - interactions(): any { return this._interactions; } - cache(): any { return this._cache; } - pubsub(): any { return this._pubsub; } - logger(name, level?): Logger { return new this._logger(name, level); } - xr(): any { return this._xr; } - i18n(): any { return this._i18n; } - - authState() { return this._authState; } - setAuthState(state: AuthState) { this._authState.next(state); } - } + authState() { + return this._authState; + } + setAuthState(state: AuthState) { + this._authState.next(state); + } +} diff --git a/packages/aws-amplify-angular/src/providers/auth.decorator.ts b/packages/aws-amplify-angular/src/providers/auth.decorator.ts index 1471bc9eeb6..63ddb9d3ac5 100644 --- a/packages/aws-amplify-angular/src/providers/auth.decorator.ts +++ b/packages/aws-amplify-angular/src/providers/auth.decorator.ts @@ -6,131 +6,135 @@ import * as _ from 'lodash'; const logger = new Logger('AuthDecorator'); function check(authState: Subject, Auth) { - // check for current authenticated user to init authState - Auth.currentAuthenticatedUser() - .then(user => { - logger.debug('has authenticated user', user); - authState.next({ state: 'signedIn', user }); - }) - .catch(err => { - logger.debug('no authenticated user', err); - authState.next({ state: 'signedOut', user: null }); - }); + // check for current authenticated user to init authState + Auth.currentAuthenticatedUser() + .then(user => { + logger.debug('has authenticated user', user); + authState.next({ state: 'signedIn', user }); + }) + .catch(err => { + logger.debug('no authenticated user', err); + authState.next({ state: 'signedOut', user: null }); + }); } function listen(authState: Subject) { - const config = Amplify.configure(null); - if (_.has(config, 'Auth.oauth')) { - Hub.listen('auth', { - onHubCapsule: capsule => { - const { channel, payload } = capsule; - if (channel === 'auth') { - const { username } = payload.data; - logger.debug('authentication oauth event', payload); - authState.next({ state: payload.event, user: { username } }); - } - } - }, 'angularAuthListener'); - } + const config = Amplify.configure(null); + if (_.has(config, 'Auth.oauth')) { + Hub.listen( + 'auth', + { + onHubCapsule: capsule => { + const { channel, payload } = capsule; + if (channel === 'auth') { + const { username } = payload.data; + logger.debug('authentication oauth event', payload); + authState.next({ state: payload.event, user: { username } }); + } + }, + }, + 'angularAuthListener' + ); + } } function decorateSignIn(authState: Subject, Auth) { - const _signIn = Auth.signIn; - Auth.signIn = ( - username: string, - password: string - ): Promise => { - return _signIn.call(Auth, username, password) - .then(user => { - logger.debug('signIn success'); - if (!user.challengeName) { - authState.next({ state: 'signedIn', user }); - return user; - } + const _signIn = Auth.signIn; + Auth.signIn = (username: string, password: string): Promise => { + return _signIn + .call(Auth, username, password) + .then(user => { + logger.debug('signIn success'); + if (!user.challengeName) { + authState.next({ state: 'signedIn', user }); + return user; + } - logger.debug('signIn challenge: ' + user.challengeName); - if (user.challengeName === 'NEW_PASSWORD_REQUIRED') { - authState.next({ state: 'requireNewPassword', user }); - } else if (user.challengeName === 'MFA_SETUP') { - authState.next({ state: 'setupMFA', user }); - } else if ( - user.challengeName === 'SMS_MFA' || - user.challengeName === 'SOFTWARE_TOKEN_MFA' - ) { - authState.next({ state: 'confirmSignIn', user }); - } else { - logger.debug('warning: unhandled challengeName ' + user.challengeName); - } - return user; - }) - .catch(err => { - logger.debug('signIn error', err); - throw err; - }); - }; + logger.debug('signIn challenge: ' + user.challengeName); + if (user.challengeName === 'NEW_PASSWORD_REQUIRED') { + authState.next({ state: 'requireNewPassword', user }); + } else if (user.challengeName === 'MFA_SETUP') { + authState.next({ state: 'setupMFA', user }); + } else if ( + user.challengeName === 'SMS_MFA' || + user.challengeName === 'SOFTWARE_TOKEN_MFA' + ) { + authState.next({ state: 'confirmSignIn', user }); + } else { + logger.debug( + 'warning: unhandled challengeName ' + user.challengeName + ); + } + return user; + }) + .catch(err => { + logger.debug('signIn error', err); + throw err; + }); + }; } function decorateSignOut(authState: Subject, Auth) { - const _signOut = Auth.signOut; - Auth.signOut = (): Promise => { - return _signOut.call(Amplify.Auth) - .then(data => { - logger.debug('signOut success'); - authState.next({ state: 'signedOut', user: null }); - return data; - }) - .catch(err => { - logger.debug('signOut error', err); - throw err; - }); - }; + const _signOut = Auth.signOut; + Auth.signOut = (): Promise => { + return _signOut + .call(Amplify.Auth) + .then(data => { + logger.debug('signOut success'); + authState.next({ state: 'signedOut', user: null }); + return data; + }) + .catch(err => { + logger.debug('signOut error', err); + throw err; + }); + }; } function decorateSignUp(authState: Subject, Auth) { - const _signUp = Auth.signUp; - Auth.signUp = ( - username: string, - password: string, - email: string, - phone_number: string - ): Promise => { - return _signUp.call(Auth, username, password, email, phone_number) - .then(data => { - logger.debug('signUp success'); - authState.next({ state: 'confirmSignUp', user: { username }}); - return data; - }) - .catch(err => { - logger.debug('signUp error', err); - throw err; - }); - }; + const _signUp = Auth.signUp; + Auth.signUp = ( + username: string, + password: string, + email: string, + phone_number: string + ): Promise => { + return _signUp + .call(Auth, username, password, email, phone_number) + .then(data => { + logger.debug('signUp success'); + authState.next({ state: 'confirmSignUp', user: { username } }); + return data; + }) + .catch(err => { + logger.debug('signUp error', err); + throw err; + }); + }; } function decorateConfirmSignUp(authState: Subject, Auth) { - const _confirmSignUp = Auth.confirmSignUp; - Auth.confirmSignUp = ( - username: string, - code: string - ): Promise => { - return _confirmSignUp.call(Auth, username, code) - .then(data => { - logger.debug('confirmSignUp success'); - authState.next({ state: 'signIn', user: { username }}); - return data; - }) - .catch(err => { - logger.debug('confirmSignUp error', err); - throw err; - }); - }; + const _confirmSignUp = Auth.confirmSignUp; + Auth.confirmSignUp = (username: string, code: string): Promise => { + return _confirmSignUp + .call(Auth, username, code) + .then(data => { + logger.debug('confirmSignUp success'); + authState.next({ state: 'signIn', user: { username } }); + return data; + }) + .catch(err => { + logger.debug('confirmSignUp error', err); + throw err; + }); + }; } export function authDecorator(authState: Subject, authModule) { - check(authState, authModule); - listen(authState); - decorateSignIn(authState, authModule); - decorateSignOut(authState, authModule); - decorateSignUp(authState, authModule); - decorateConfirmSignUp(authState, authModule); + check(authState, authModule); + listen(authState); + decorateSignIn(authState, authModule); + decorateSignOut(authState, authModule); + decorateSignUp(authState, authModule); + decorateConfirmSignUp(authState, authModule); } diff --git a/packages/aws-amplify-angular/src/providers/auth.state.ts b/packages/aws-amplify-angular/src/providers/auth.state.ts index bd388d7ebbf..4ce5d2a5b96 100644 --- a/packages/aws-amplify-angular/src/providers/auth.state.ts +++ b/packages/aws-amplify-angular/src/providers/auth.state.ts @@ -1,4 +1,4 @@ export interface AuthState { - state: string; // signedOut, signedIn, mfaRequired, newPasswordRequired - user: any; + state: string; // signedOut, signedIn, mfaRequired, newPasswordRequired + user: any; } diff --git a/packages/aws-amplify-angular/src/providers/index.ts b/packages/aws-amplify-angular/src/providers/index.ts index b22964b2903..40dfd60833a 100644 --- a/packages/aws-amplify-angular/src/providers/index.ts +++ b/packages/aws-amplify-angular/src/providers/index.ts @@ -1,4 +1,3 @@ export { AmplifyService } from './amplify.service'; export { AuthState } from './auth.state'; export { default as AmplifyModules } from './amplify.compose.service'; - diff --git a/packages/aws-amplify-angular/test_setup/setup-jest.ts b/packages/aws-amplify-angular/test_setup/setup-jest.ts index a9ae53fd1e9..d81ecbe1a6b 100644 --- a/packages/aws-amplify-angular/test_setup/setup-jest.ts +++ b/packages/aws-amplify-angular/test_setup/setup-jest.ts @@ -1,22 +1,24 @@ import 'jest-preset-angular'; -window.alert = (msg) => { console.log(msg); }; +window.alert = msg => { + console.log(msg); +}; -function noOp () { } +function noOp() {} if (typeof window.URL.createObjectURL === 'undefined') { - Object.defineProperty(window.URL, 'createObjectURL', { value: noOp}) + Object.defineProperty(window.URL, 'createObjectURL', { value: noOp }); } class Worker { - constructor(stringUrl) { - this.url = stringUrl; - this.onmessage = () => {}; - } + constructor(stringUrl) { + this.url = stringUrl; + this.onmessage = () => {}; + } - postMessage(msg) { - this.onmessage(msg); - } + postMessage(msg) { + this.onmessage(msg); + } } -window.Worker = Worker; \ No newline at end of file +window.Worker = Worker; diff --git a/packages/aws-amplify-angular/tslint.json b/packages/aws-amplify-angular/tslint.json index d56ac1a36b3..1bb9e144d24 100644 --- a/packages/aws-amplify-angular/tslint.json +++ b/packages/aws-amplify-angular/tslint.json @@ -1,72 +1,45 @@ - { - "defaultSeverity": "error", - "plugins": [ - "prettier" - ], - "extends": [ - //"tslint-config-airbnb" - ], - "jsRules": {}, - "rules": { - "prefer-const": true, - "max-line-length": [true, 100], - "no-empty-interface": true, - "no-var-keyword": true, - "object-literal-shorthand": true, - "no-eval": true, - "space-before-function-paren": [ - true, - { - "anonymous": "never", - "named": "never" - } - ], - "no-parameter-reassignment": true, - "align": [ - true, - "arguments", - "parameters" - ], - "no-duplicate-imports": true, - "one-variable-per-declaration": [ - false, - "ignore-for-loop" - ], - "triple-equals": [ - true, - "allow-null-check" - ], - "no-boolean-literal-compare": true, - "comment-format": [ - true, - "check-space" - ], - "indent": [ - true, - "space", - 2 - ], - "whitespace": [ - false, - "check-branch", - "check-decl", - "check-operator", - "check-preblock" - ], - "eofline": true, - "variable-name": [ - true, - "check-format", // 22.2 - "allow-pascal-case", - "allow-snake-case", - "allow-leading-underscore" - ], - "semicolon": [ - true, - "always", - "ignore-interfaces" - ] - }, - "rulesDirectory": [] -} \ No newline at end of file + "defaultSeverity": "error", + "plugins": ["prettier"], + "extends": [], + "jsRules": {}, + "rules": { + "prefer-const": true, + "max-line-length": [true, 120], + "no-empty-interface": true, + "no-var-keyword": true, + "object-literal-shorthand": true, + "no-eval": true, + "space-before-function-paren": [ + true, + { + "anonymous": "never", + "named": "never" + } + ], + "no-parameter-reassignment": true, + "align": [true, "parameters"], + "no-duplicate-imports": true, + "one-variable-per-declaration": [false, "ignore-for-loop"], + "triple-equals": [true, "allow-null-check"], + "comment-format": [true, "check-space"], + "indent": [false], + "whitespace": [ + false, + "check-branch", + "check-decl", + "check-operator", + "check-preblock" + ], + "eofline": true, + "variable-name": [ + true, + "check-format", + "allow-pascal-case", + "allow-snake-case", + "allow-leading-underscore" + ], + "semicolon": [true, "always", "ignore-interfaces"] + }, + "rulesDirectory": [] +} diff --git a/packages/aws-amplify-react-native/CHANGELOG.md b/packages/aws-amplify-react-native/CHANGELOG.md index a09d6011de3..1834a6382c4 100644 --- a/packages/aws-amplify-react-native/CHANGELOG.md +++ b/packages/aws-amplify-react-native/CHANGELOG.md @@ -7,1772 +7,1326 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package aws-amplify-react-native - - - - ## [2.1.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.16...aws-amplify-react-native@2.1.17) (2019-09-04) - ### Bug Fixes -* **aws-amplify-react-native:** Add countryDialCodes to allow non USA phone numbers ([#3593](https://github.com/aws/aws-amplify/issues/3593)) ([9791966](https://github.com/aws/aws-amplify/commit/9791966)) -* **aws-amplify-react-native:** removing axios dependency on amplify-react-native ([4c5b7cf](https://github.com/aws/aws-amplify/commit/4c5b7cf)) -* **aws-amplify-react-native:** Use more compatible default export syntax ([#3102](https://github.com/aws/aws-amplify/issues/3102)) ([3ed0b74](https://github.com/aws/aws-amplify/commit/3ed0b74)) - - - - +- **aws-amplify-react-native:** Add countryDialCodes to allow non USA phone numbers ([#3593](https://github.com/aws/aws-amplify/issues/3593)) ([9791966](https://github.com/aws/aws-amplify/commit/9791966)) +- **aws-amplify-react-native:** removing axios dependency on amplify-react-native ([4c5b7cf](https://github.com/aws/aws-amplify/commit/4c5b7cf)) +- **aws-amplify-react-native:** Use more compatible default export syntax ([#3102](https://github.com/aws/aws-amplify/issues/3102)) ([3ed0b74](https://github.com/aws/aws-amplify/commit/3ed0b74)) ## [2.1.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.15...aws-amplify-react-native@2.1.16) (2019-07-30) **Note:** Version bump only for package aws-amplify-react-native - - - - ## [2.1.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.14...aws-amplify-react-native@2.1.15) (2019-07-18) **Note:** Version bump only for package aws-amplify-react-native - - - - -## [2.1.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.14-unstable.0...aws-amplify-react-native@2.1.14) (2019-07-09) - - +## [2.1.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.14-unstable.0...aws-amplify-react-native@2.1.14) (2019-07-09) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.14-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.13...aws-amplify-react-native@2.1.14-unstable.0) (2019-06-27) - - +## [2.1.14-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.13...aws-amplify-react-native@2.1.14-unstable.0) (2019-06-27) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.13-unstable.3...aws-amplify-react-native@2.1.13) (2019-06-17) - - +## [2.1.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.13-unstable.3...aws-amplify-react-native@2.1.13) (2019-06-17) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.13-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.13-unstable.2...aws-amplify-react-native@2.1.13-unstable.3) (2019-06-12) +## [2.1.13-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.13-unstable.2...aws-amplify-react-native@2.1.13-unstable.3) (2019-06-12) ### Bug Fixes -* **aws-amplify-react-native:** Remove console log ([#3305](https://github.com/aws/aws-amplify/issues/3305)) ([f03b09c](https://github.com/aws/aws-amplify/commit/f03b09c)) - - - +- **aws-amplify-react-native:** Remove console log ([#3305](https://github.com/aws/aws-amplify/issues/3305)) ([f03b09c](https://github.com/aws/aws-amplify/commit/f03b09c)) -## [2.1.13-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.13-unstable.1...aws-amplify-react-native@2.1.13-unstable.2) (2019-05-24) +## [2.1.13-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.13-unstable.1...aws-amplify-react-native@2.1.13-unstable.2) (2019-05-24) ### Bug Fixes -* **aws-amplify-react-native:** Fix awSignUpConfig.defaultCountryCode not being used ([9cec669](https://github.com/aws/aws-amplify/commit/9cec669)) - - - +- **aws-amplify-react-native:** Fix awSignUpConfig.defaultCountryCode not being used ([9cec669](https://github.com/aws/aws-amplify/commit/9cec669)) -## [2.1.13-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.13-unstable.0...aws-amplify-react-native@2.1.13-unstable.1) (2019-05-24) - - +## [2.1.13-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.13-unstable.0...aws-amplify-react-native@2.1.13-unstable.1) (2019-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.13-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.12...aws-amplify-react-native@2.1.13-unstable.0) (2019-05-24) - - +## [2.1.13-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.12...aws-amplify-react-native@2.1.13-unstable.0) (2019-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.12-unstable.0...aws-amplify-react-native@2.1.12) (2019-05-14) - - +## [2.1.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.12-unstable.0...aws-amplify-react-native@2.1.12) (2019-05-14) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.12-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.11...aws-amplify-react-native@2.1.12-unstable.0) (2019-05-13) +## [2.1.12-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.11...aws-amplify-react-native@2.1.12-unstable.0) (2019-05-13) ### Features -* **aws-amplify-react-native:** withOAuth Loading ([97ff79c](https://github.com/aws/aws-amplify/commit/97ff79c)), closes [#3021](https://github.com/aws/aws-amplify/issues/3021) - - - +- **aws-amplify-react-native:** withOAuth Loading ([97ff79c](https://github.com/aws/aws-amplify/commit/97ff79c)), closes [#3021](https://github.com/aws/aws-amplify/issues/3021) -## [2.1.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.11-unstable.3...aws-amplify-react-native@2.1.11) (2019-05-06) - - +## [2.1.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.11-unstable.3...aws-amplify-react-native@2.1.11) (2019-05-06) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.11-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.11-unstable.2...aws-amplify-react-native@2.1.11-unstable.3) (2019-05-04) +## [2.1.11-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.11-unstable.2...aws-amplify-react-native@2.1.11-unstable.3) (2019-05-04) ### Bug Fixes -* **aws-amplify-react-native:** Fix funky background ([f6bc2ba](https://github.com/aws/aws-amplify/commit/f6bc2ba)), closes [#2618](https://github.com/aws/aws-amplify/issues/2618) - - - +- **aws-amplify-react-native:** Fix funky background ([f6bc2ba](https://github.com/aws/aws-amplify/commit/f6bc2ba)), closes [#2618](https://github.com/aws/aws-amplify/issues/2618) -## [2.1.11-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.11-unstable.1...aws-amplify-react-native@2.1.11-unstable.2) (2019-05-03) - - +## [2.1.11-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.11-unstable.1...aws-amplify-react-native@2.1.11-unstable.2) (2019-05-03) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.11-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.11-unstable.0...aws-amplify-react-native@2.1.11-unstable.1) (2019-04-26) +## [2.1.11-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.11-unstable.0...aws-amplify-react-native@2.1.11-unstable.1) (2019-04-26) ### Bug Fixes -* **aws-amplify-react-native:** sets inital value of pickAttr to email or phone_number so that verify button is enabled and passes the correct value to verification method ([3cf4915](https://github.com/aws/aws-amplify/commit/3cf4915)) - - - +- **aws-amplify-react-native:** sets inital value of pickAttr to email or phone_number so that verify button is enabled and passes the correct value to verification method ([3cf4915](https://github.com/aws/aws-amplify/commit/3cf4915)) -## [2.1.11-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.10...aws-amplify-react-native@2.1.11-unstable.0) (2019-04-17) +## [2.1.11-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.10...aws-amplify-react-native@2.1.11-unstable.0) (2019-04-17) ### Bug Fixes -* **aws-amplify-react-native:** catch the error when verifying contact ([f8c9972](https://github.com/aws/aws-amplify/commit/f8c9972)) - - - +- **aws-amplify-react-native:** catch the error when verifying contact ([f8c9972](https://github.com/aws/aws-amplify/commit/f8c9972)) -## [2.1.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.10-unstable.0...aws-amplify-react-native@2.1.10) (2019-04-09) - - +## [2.1.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.10-unstable.0...aws-amplify-react-native@2.1.10) (2019-04-09) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.10-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.9...aws-amplify-react-native@2.1.10-unstable.0) (2019-04-08) +## [2.1.10-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.9...aws-amplify-react-native@2.1.10-unstable.0) (2019-04-08) ### Features -* **@aws-amplify/auth:** Easier Federation with OAuth ([#3005](https://github.com/aws/aws-amplify/issues/3005)) ([76cde59](https://github.com/aws/aws-amplify/commit/76cde59)) - - - +- **@aws-amplify/auth:** Easier Federation with OAuth ([#3005](https://github.com/aws/aws-amplify/issues/3005)) ([76cde59](https://github.com/aws/aws-amplify/commit/76cde59)) -## [2.1.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.9-unstable.0...aws-amplify-react-native@2.1.9) (2019-03-28) - - +## [2.1.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.9-unstable.0...aws-amplify-react-native@2.1.9) (2019-03-28) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.9-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.8...aws-amplify-react-native@2.1.9-unstable.0) (2019-03-28) - - +## [2.1.9-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.8...aws-amplify-react-native@2.1.9-unstable.0) (2019-03-28) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.8-unstable.2...aws-amplify-react-native@2.1.8) (2019-03-04) - - +## [2.1.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.8-unstable.2...aws-amplify-react-native@2.1.8) (2019-03-04) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.8-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.8-unstable.1...aws-amplify-react-native@2.1.8-unstable.2) (2019-03-04) +## [2.1.8-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.8-unstable.1...aws-amplify-react-native@2.1.8-unstable.2) (2019-03-04) ### Features -* **aws-amplify-react-native:** Add withOAuth HOC for Cognito Hosted UI ([#2665](https://github.com/aws/aws-amplify/issues/2665)) ([ac4d232](https://github.com/aws/aws-amplify/commit/ac4d232)) - - - +- **aws-amplify-react-native:** Add withOAuth HOC for Cognito Hosted UI ([#2665](https://github.com/aws/aws-amplify/issues/2665)) ([ac4d232](https://github.com/aws/aws-amplify/commit/ac4d232)) -## [2.1.8-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.8-unstable.0...aws-amplify-react-native@2.1.8-unstable.1) (2019-02-27) - - +## [2.1.8-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.8-unstable.0...aws-amplify-react-native@2.1.8-unstable.1) (2019-02-27) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.8-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.7...aws-amplify-react-native@2.1.8-unstable.0) (2019-01-18) - - +## [2.1.8-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.7...aws-amplify-react-native@2.1.8-unstable.0) (2019-01-18) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.6...aws-amplify-react-native@2.1.7) (2019-01-10) - - +## [2.1.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.6...aws-amplify-react-native@2.1.7) (2019-01-10) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.6-unstable.1...aws-amplify-react-native@2.1.6) (2018-12-26) - - +## [2.1.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.6-unstable.1...aws-amplify-react-native@2.1.6) (2018-12-26) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.6-unstable.0...aws-amplify-react-native@2.1.6-unstable.1) (2018-12-24) - - +## [2.1.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.6-unstable.0...aws-amplify-react-native@2.1.6-unstable.1) (2018-12-24) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.5...aws-amplify-react-native@2.1.6-unstable.0) (2018-12-15) +## [2.1.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.5...aws-amplify-react-native@2.1.6-unstable.0) (2018-12-15) ### Features -* **@aws-amplify/react-native:** React Native chatbot voice interactions ([#2355](https://github.com/aws/aws-amplify/issues/2355)) ([2a4f4bc](https://github.com/aws/aws-amplify/commit/2a4f4bc)) - - - +- **@aws-amplify/react-native:** React Native chatbot voice interactions ([#2355](https://github.com/aws/aws-amplify/issues/2355)) ([2a4f4bc](https://github.com/aws/aws-amplify/commit/2a4f4bc)) -## [2.1.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.2-unstable.3...aws-amplify-react-native@2.1.5) (2018-12-15) - - +## [2.1.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.2-unstable.3...aws-amplify-react-native@2.1.5) (2018-12-15) **Note:** Version bump only for package aws-amplify-react-native + ## [2.1.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.2-unstable.2...aws-amplify-react-native@2.1.4) (2018-12-14) -## [2.1.2-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.2-unstable.2...aws-amplify-react-native@2.1.2-unstable.3) (2018-12-14) - - - +## [2.1.2-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.2-unstable.2...aws-amplify-react-native@2.1.2-unstable.3) (2018-12-14) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.2-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.2-unstable.1...aws-amplify-react-native@2.1.2-unstable.2) (2018-12-14) +## [2.1.2-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.2-unstable.1...aws-amplify-react-native@2.1.2-unstable.2) (2018-12-14) -## [2.1.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.2-unstable.1...aws-amplify-react-native@2.1.2) (2018-12-14) - - - +## [2.1.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.2-unstable.1...aws-amplify-react-native@2.1.2) (2018-12-14) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.2-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.2-unstable.0...aws-amplify-react-native@2.1.2-unstable.1) (2018-12-14) - - +## [2.1.2-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.2-unstable.0...aws-amplify-react-native@2.1.2-unstable.1) (2018-12-14) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1...aws-amplify-react-native@2.1.2-unstable.0) (2018-12-13) +## [2.1.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1...aws-amplify-react-native@2.1.2-unstable.0) (2018-12-13) ### Features -* **@aws-amplify/interactions @aws-amplify/react @aws-amplify/react-native @aws-amplify/angular @aws-amplify/vue:** Update interactions to include voice ([#2121](https://github.com/aws/aws-amplify/issues/2121)) ([938d2a5](https://github.com/aws/aws-amplify/commit/938d2a5)) - - - +- **@aws-amplify/interactions @aws-amplify/react @aws-amplify/react-native @aws-amplify/angular @aws-amplify/vue:** Update interactions to include voice ([#2121](https://github.com/aws/aws-amplify/issues/2121)) ([938d2a5](https://github.com/aws/aws-amplify/commit/938d2a5)) -## [2.1.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-unstable.3...aws-amplify-react-native@2.1.1) (2018-12-13) - - +## [2.1.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-unstable.3...aws-amplify-react-native@2.1.1) (2018-12-13) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.1-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-unstable.2...aws-amplify-react-native@2.1.1-unstable.3) (2018-12-13) - - +## [2.1.1-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-unstable.2...aws-amplify-react-native@2.1.1-unstable.3) (2018-12-13) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-unstable.1...aws-amplify-react-native@2.1.1-unstable.2) (2018-12-13) - - +## [2.1.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-unstable.1...aws-amplify-react-native@2.1.1-unstable.2) (2018-12-13) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-unstable.0...aws-amplify-react-native@2.1.1-unstable.1) (2018-12-11) - - +## [2.1.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-unstable.0...aws-amplify-react-native@2.1.1-unstable.1) (2018-12-11) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.12-unstable.0...aws-amplify-react-native@2.1.1-unstable.0) (2018-12-10) - - +## [2.1.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.12-unstable.0...aws-amplify-react-native@2.1.1-unstable.0) (2018-12-10) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.12-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.11...aws-amplify-react-native@2.0.12-unstable.0) (2018-12-07) - - +## [2.0.12-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.11...aws-amplify-react-native@2.0.12-unstable.0) (2018-12-07) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.10...aws-amplify-react-native@2.0.11) (2018-12-07) - - +## [2.0.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.10...aws-amplify-react-native@2.0.11) (2018-12-07) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.11-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.10...aws-amplify-react-native@2.0.11-unstable.0) (2018-12-06) - - +## [2.0.11-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.10...aws-amplify-react-native@2.0.11-unstable.0) (2018-12-06) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.9...aws-amplify-react-native@2.0.10) (2018-12-06) - - +## [2.0.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.9...aws-amplify-react-native@2.0.10) (2018-12-06) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.10-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.10-unstable.0...aws-amplify-react-native@2.0.10-unstable.1) (2018-12-04) - - +## [2.0.10-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.10-unstable.0...aws-amplify-react-native@2.0.10-unstable.1) (2018-12-04) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.10-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.9...aws-amplify-react-native@2.0.10-unstable.0) (2018-12-04) - - +## [2.0.10-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.9...aws-amplify-react-native@2.0.10-unstable.0) (2018-12-04) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.9-unstable.2...aws-amplify-react-native@2.0.9) (2018-12-03) - - +## [2.0.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.9-unstable.2...aws-amplify-react-native@2.0.9) (2018-12-03) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.9-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.9-unstable.1...aws-amplify-react-native@2.0.9-unstable.2) (2018-12-03) +## [2.0.9-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.9-unstable.1...aws-amplify-react-native@2.0.9-unstable.2) (2018-12-03) ### Features -* **@aws-amplify/react-native:** Add dial code selector to sign-up ([ab5efc3](https://github.com/aws/aws-amplify/commit/ab5efc3)) - - - +- **@aws-amplify/react-native:** Add dial code selector to sign-up ([ab5efc3](https://github.com/aws/aws-amplify/commit/ab5efc3)) -## [2.0.9-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.9-unstable.0...aws-amplify-react-native@2.0.9-unstable.1) (2018-11-29) +## [2.0.9-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.9-unstable.0...aws-amplify-react-native@2.0.9-unstable.1) (2018-11-29) ### Bug Fixes -* **aws-amplify-react-native:** render required attributes when requiring new passwords ([faa502f](https://github.com/aws/aws-amplify/commit/faa502f)) - +- **aws-amplify-react-native:** render required attributes when requiring new passwords ([faa502f](https://github.com/aws/aws-amplify/commit/faa502f)) -## [2.0.9-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.8...aws-amplify-react-native@2.0.9-unstable.0) (2018-11-23) +## [2.0.9-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.8...aws-amplify-react-native@2.0.9-unstable.0) (2018-11-23) ### Bug Fixes -* **aws-amplify-react:** add I18n in Greetings ([e549db7](https://github.com/aws/aws-amplify/commit/e549db7)) - +- **aws-amplify-react:** add I18n in Greetings ([e549db7](https://github.com/aws/aws-amplify/commit/e549db7)) **Note:** Version bump only for package aws-amplify-react-native - -## [2.1.1-beta.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-beta.2...aws-amplify-react-native@2.1.1-beta.3) (2018-11-15) - - +## [2.1.1-beta.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-beta.2...aws-amplify-react-native@2.1.1-beta.3) (2018-11-15) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.1-beta.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-beta.1...aws-amplify-react-native@2.1.1-beta.2) (2018-11-14) - - +## [2.1.1-beta.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-beta.1...aws-amplify-react-native@2.1.1-beta.2) (2018-11-14) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.1-beta.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-beta.0...aws-amplify-react-native@2.1.1-beta.1) (2018-11-14) - +## [2.1.1-beta.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.1.1-beta.0...aws-amplify-react-native@2.1.1-beta.1) (2018-11-14) **Note:** Version bump only for package aws-amplify-react-native -## [2.1.1-beta.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.8...aws-amplify-react-native@2.1.1-beta.0) (2018-11-02) - - +## [2.1.1-beta.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.8...aws-amplify-react-native@2.1.1-beta.0) (2018-11-02) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.8-unstable.0...aws-amplify-react-native@2.0.8) (2018-10-29) - - +## [2.0.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.8-unstable.0...aws-amplify-react-native@2.0.8) (2018-10-29) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.8-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.7...aws-amplify-react-native@2.0.8-unstable.0) (2018-10-25) +## [2.0.8-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.7...aws-amplify-react-native@2.0.8-unstable.0) (2018-10-25) ### Bug Fixes -* **aws-amplify-react aws-amplify-react-native:** Connect component ([#1868](https://github.com/aws/aws-amplify/issues/1868)) ([8dd6b55](https://github.com/aws/aws-amplify/commit/8dd6b55)) - - - +- **aws-amplify-react aws-amplify-react-native:** Connect component ([#1868](https://github.com/aws/aws-amplify/issues/1868)) ([8dd6b55](https://github.com/aws/aws-amplify/commit/8dd6b55)) -## [2.0.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.7-unstable.1...aws-amplify-react-native@2.0.7) (2018-10-17) - - +## [2.0.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.7-unstable.1...aws-amplify-react-native@2.0.7) (2018-10-17) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.7-unstable.0...aws-amplify-react-native@2.0.7-unstable.1) (2018-10-08) +## [2.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.7-unstable.0...aws-amplify-react-native@2.0.7-unstable.1) (2018-10-08) ### Bug Fixes -* **aws-amplify-react:** jump to the initial state if not signed in ([d8779eb](https://github.com/aws/aws-amplify/commit/d8779eb)) - - - +- **aws-amplify-react:** jump to the initial state if not signed in ([d8779eb](https://github.com/aws/aws-amplify/commit/d8779eb)) -## [2.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.6-unstable.0...aws-amplify-react-native@2.0.7-unstable.0) (2018-10-05) - - +## [2.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.6-unstable.0...aws-amplify-react-native@2.0.7-unstable.0) (2018-10-05) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.6-unstable.0...aws-amplify-react-native@2.0.6) (2018-10-04) - - +## [2.0.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.6-unstable.0...aws-amplify-react-native@2.0.6) (2018-10-04) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.5-unstable.0...aws-amplify-react-native@2.0.6-unstable.0) (2018-10-03) - - +## [2.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.5-unstable.0...aws-amplify-react-native@2.0.6-unstable.0) (2018-10-03) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.5-unstable.0...aws-amplify-react-native@2.0.5) (2018-10-03) - - +## [2.0.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.5-unstable.0...aws-amplify-react-native@2.0.5) (2018-10-03) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.4...aws-amplify-react-native@2.0.5-unstable.0) (2018-09-28) - - +## [2.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.4...aws-amplify-react-native@2.0.5-unstable.0) (2018-09-28) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.4-unstable.0...aws-amplify-react-native@2.0.4) (2018-09-27) - - +## [2.0.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.4-unstable.0...aws-amplify-react-native@2.0.4) (2018-09-27) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.3...aws-amplify-react-native@2.0.4-unstable.0) (2018-09-24) +## [2.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.3...aws-amplify-react-native@2.0.4-unstable.0) (2018-09-24) ### Bug Fixes -* **aws-amplify-react-native:** check contact before getting signed in ([5707577](https://github.com/aws/aws-amplify/commit/5707577)) - - - +- **aws-amplify-react-native:** check contact before getting signed in ([5707577](https://github.com/aws/aws-amplify/commit/5707577)) -## [2.0.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.3-unstable.0...aws-amplify-react-native@2.0.3) (2018-09-21) - - +## [2.0.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.3-unstable.0...aws-amplify-react-native@2.0.3) (2018-09-21) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.1...aws-amplify-react-native@2.0.3-unstable.0) (2018-09-21) - - +## [2.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.1...aws-amplify-react-native@2.0.3-unstable.0) (2018-09-21) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.1...aws-amplify-react-native@2.0.2) (2018-09-21) - - +## [2.0.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.1...aws-amplify-react-native@2.0.2) (2018-09-21) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.1-unstable.3...aws-amplify-react-native@2.0.1) (2018-09-09) - - +## [2.0.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.1-unstable.3...aws-amplify-react-native@2.0.1) (2018-09-09) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.1-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.1-unstable.2...aws-amplify-react-native@2.0.1-unstable.3) (2018-09-08) - - +## [2.0.1-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.1-unstable.2...aws-amplify-react-native@2.0.1-unstable.3) (2018-09-08) **Note:** Version bump only for package aws-amplify-react-native -## [2.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.0...aws-amplify-react-native@2.0.1-unstable.2) (2018-09-05) +## [2.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.0...aws-amplify-react-native@2.0.1-unstable.2) (2018-09-05) ### Bug Fixes -* **aws-amplify-react-native:** fix the link in the requireNewPassword component ([bdd816a](https://github.com/aws/aws-amplify/commit/bdd816a)) - - - +- **aws-amplify-react-native:** fix the link in the requireNewPassword component ([bdd816a](https://github.com/aws/aws-amplify/commit/bdd816a)) -## [2.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.0...aws-amplify-react-native@2.0.1-unstable.1) (2018-08-30) +## [2.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@2.0.0...aws-amplify-react-native@2.0.1-unstable.1) (2018-08-30) ### Bug Fixes -* **aws-amplify-react-native:** fix the link in the requireNewPassword component ([bdd816a](https://github.com/aws/aws-amplify/commit/bdd816a)) - - - +- **aws-amplify-react-native:** fix the link in the requireNewPassword component ([bdd816a](https://github.com/aws/aws-amplify/commit/bdd816a)) -# [2.0.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.26...aws-amplify-react-native@2.0.0) (2018-08-28) +# [2.0.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.26...aws-amplify-react-native@2.0.0) (2018-08-28) ### Features -* UI Components ([1ff1abd](https://github.com/aws/aws-amplify/commit/1ff1abd)) - +- UI Components ([1ff1abd](https://github.com/aws/aws-amplify/commit/1ff1abd)) ### BREAKING CHANGES -* UI Components - - - +- UI Components -## [1.0.7-unstable.26](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.25...aws-amplify-react-native@1.0.7-unstable.26) (2018-08-28) +## [1.0.7-unstable.26](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.25...aws-amplify-react-native@1.0.7-unstable.26) (2018-08-28) -* Amplify ui migration (#1517) ([41d3184](https://github.com/aws/aws-amplify/commit/41d3184)), closes [#1517](https://github.com/aws/aws-amplify/issues/1517) - +- Amplify ui migration (#1517) ([41d3184](https://github.com/aws/aws-amplify/commit/41d3184)), closes [#1517](https://github.com/aws/aws-amplify/issues/1517) ### BREAKING CHANGES -* UI Components - - - +- UI Components -## [1.0.7-unstable.25](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.24...aws-amplify-react-native@1.0.7-unstable.25) (2018-08-27) - - +## [1.0.7-unstable.25](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.24...aws-amplify-react-native@1.0.7-unstable.25) (2018-08-27) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.24](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.23...aws-amplify-react-native@1.0.7-unstable.24) (2018-08-27) - - +## [1.0.7-unstable.24](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.23...aws-amplify-react-native@1.0.7-unstable.24) (2018-08-27) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.23](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.21...aws-amplify-react-native@1.0.7-unstable.23) (2018-08-27) - - +## [1.0.7-unstable.23](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.21...aws-amplify-react-native@1.0.7-unstable.23) (2018-08-27) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.22](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.21...aws-amplify-react-native@1.0.7-unstable.22) (2018-08-25) - - +## [1.0.7-unstable.22](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.21...aws-amplify-react-native@1.0.7-unstable.22) (2018-08-25) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.21](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.20...aws-amplify-react-native@1.0.7-unstable.21) (2018-08-24) - - +## [1.0.7-unstable.21](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.20...aws-amplify-react-native@1.0.7-unstable.21) (2018-08-24) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.20](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.19...aws-amplify-react-native@1.0.7-unstable.20) (2018-08-24) - - +## [1.0.7-unstable.20](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.19...aws-amplify-react-native@1.0.7-unstable.20) (2018-08-24) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.19](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.17...aws-amplify-react-native@1.0.7-unstable.19) (2018-08-24) - - +## [1.0.7-unstable.19](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.17...aws-amplify-react-native@1.0.7-unstable.19) (2018-08-24) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.18](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.17...aws-amplify-react-native@1.0.7-unstable.18) (2018-08-24) - - +## [1.0.7-unstable.18](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.17...aws-amplify-react-native@1.0.7-unstable.18) (2018-08-24) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.15...aws-amplify-react-native@1.0.7-unstable.17) (2018-08-24) - - +## [1.0.7-unstable.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.15...aws-amplify-react-native@1.0.7-unstable.17) (2018-08-24) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.15...aws-amplify-react-native@1.0.7-unstable.16) (2018-08-24) - - +## [1.0.7-unstable.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.15...aws-amplify-react-native@1.0.7-unstable.16) (2018-08-24) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.14...aws-amplify-react-native@1.0.7-unstable.15) (2018-08-24) - - +## [1.0.7-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.14...aws-amplify-react-native@1.0.7-unstable.15) (2018-08-24) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.13...aws-amplify-react-native@1.0.7-unstable.14) (2018-08-24) - - +## [1.0.7-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.13...aws-amplify-react-native@1.0.7-unstable.14) (2018-08-24) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.11...aws-amplify-react-native@1.0.7-unstable.13) (2018-08-23) - - +## [1.0.7-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.11...aws-amplify-react-native@1.0.7-unstable.13) (2018-08-23) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.11...aws-amplify-react-native@1.0.7-unstable.12) (2018-08-23) - - +## [1.0.7-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.11...aws-amplify-react-native@1.0.7-unstable.12) (2018-08-23) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.10...aws-amplify-react-native@1.0.7-unstable.11) (2018-08-23) - - +## [1.0.7-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.10...aws-amplify-react-native@1.0.7-unstable.11) (2018-08-23) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.9...aws-amplify-react-native@1.0.7-unstable.10) (2018-08-23) - - +## [1.0.7-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.9...aws-amplify-react-native@1.0.7-unstable.10) (2018-08-23) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.8...aws-amplify-react-native@1.0.7-unstable.9) (2018-08-23) - - +## [1.0.7-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.8...aws-amplify-react-native@1.0.7-unstable.9) (2018-08-23) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.7...aws-amplify-react-native@1.0.7-unstable.8) (2018-08-22) - - +## [1.0.7-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.7...aws-amplify-react-native@1.0.7-unstable.8) (2018-08-22) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.6...aws-amplify-react-native@1.0.7-unstable.7) (2018-08-22) - - +## [1.0.7-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.6...aws-amplify-react-native@1.0.7-unstable.7) (2018-08-22) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.5...aws-amplify-react-native@1.0.7-unstable.6) (2018-08-21) - - +## [1.0.7-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.5...aws-amplify-react-native@1.0.7-unstable.6) (2018-08-21) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.4...aws-amplify-react-native@1.0.7-unstable.5) (2018-08-21) - - +## [1.0.7-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.4...aws-amplify-react-native@1.0.7-unstable.5) (2018-08-21) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.3...aws-amplify-react-native@1.0.7-unstable.4) (2018-08-20) - - +## [1.0.7-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.3...aws-amplify-react-native@1.0.7-unstable.4) (2018-08-20) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.2...aws-amplify-react-native@1.0.7-unstable.3) (2018-08-19) - - +## [1.0.7-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.2...aws-amplify-react-native@1.0.7-unstable.3) (2018-08-19) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.1...aws-amplify-react-native@1.0.7-unstable.2) (2018-08-18) - - +## [1.0.7-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.1...aws-amplify-react-native@1.0.7-unstable.2) (2018-08-18) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.0...aws-amplify-react-native@1.0.7-unstable.1) (2018-08-16) +## [1.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.7-unstable.0...aws-amplify-react-native@1.0.7-unstable.1) (2018-08-16) ### Bug Fixes -* **aws-amplify-react-native:** fix the Authenticator to only call async functions when mounted ([8352bdb](https://github.com/aws/aws-amplify/commit/8352bdb)) - - - +- **aws-amplify-react-native:** fix the Authenticator to only call async functions when mounted ([8352bdb](https://github.com/aws/aws-amplify/commit/8352bdb)) -## [1.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6...aws-amplify-react-native@1.0.7-unstable.0) (2018-08-15) - - +## [1.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6...aws-amplify-react-native@1.0.7-unstable.0) (2018-08-15) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.5...aws-amplify-react-native@1.0.6) (2018-08-14) - - +## [1.0.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.5...aws-amplify-react-native@1.0.6) (2018-08-14) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.6-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.4...aws-amplify-react-native@1.0.6-unstable.5) (2018-08-14) +## [1.0.6-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.4...aws-amplify-react-native@1.0.6-unstable.5) (2018-08-14) ### Bug Fixes -* **aws-amplify-react-native:** move keyboard dismiss from authenticator to child components ([5d2b77a](https://github.com/aws/aws-amplify/commit/5d2b77a)) - - - +- **aws-amplify-react-native:** move keyboard dismiss from authenticator to child components ([5d2b77a](https://github.com/aws/aws-amplify/commit/5d2b77a)) -## [1.0.6-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.3...aws-amplify-react-native@1.0.6-unstable.4) (2018-08-13) - - +## [1.0.6-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.3...aws-amplify-react-native@1.0.6-unstable.4) (2018-08-13) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.6-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.2...aws-amplify-react-native@1.0.6-unstable.3) (2018-08-13) - - +## [1.0.6-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.2...aws-amplify-react-native@1.0.6-unstable.3) (2018-08-13) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.1...aws-amplify-react-native@1.0.6-unstable.2) (2018-08-09) - - +## [1.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.1...aws-amplify-react-native@1.0.6-unstable.2) (2018-08-09) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.0...aws-amplify-react-native@1.0.6-unstable.1) (2018-08-07) - - +## [1.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.6-unstable.0...aws-amplify-react-native@1.0.6-unstable.1) (2018-08-07) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5...aws-amplify-react-native@1.0.6-unstable.0) (2018-08-07) - - +## [1.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5...aws-amplify-react-native@1.0.6-unstable.0) (2018-08-07) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.7...aws-amplify-react-native@1.0.5) (2018-08-06) - - +## [1.0.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.7...aws-amplify-react-native@1.0.5) (2018-08-06) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.5-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.6...aws-amplify-react-native@1.0.5-unstable.7) (2018-08-06) +## [1.0.5-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.6...aws-amplify-react-native@1.0.5-unstable.7) (2018-08-06) ### Bug Fixes -* **aws-amplify-react-native:** fix the footer of confirmSignIn component ([a3443ee](https://github.com/aws/aws-amplify/commit/a3443ee)) - - - +- **aws-amplify-react-native:** fix the footer of confirmSignIn component ([a3443ee](https://github.com/aws/aws-amplify/commit/a3443ee)) -## [1.0.5-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.5...aws-amplify-react-native@1.0.5-unstable.6) (2018-08-06) - - +## [1.0.5-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.5...aws-amplify-react-native@1.0.5-unstable.6) (2018-08-06) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.5-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.3...aws-amplify-react-native@1.0.5-unstable.5) (2018-08-06) - - +## [1.0.5-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.3...aws-amplify-react-native@1.0.5-unstable.5) (2018-08-06) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.5-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.2...aws-amplify-react-native@1.0.5-unstable.3) (2018-07-31) - - +## [1.0.5-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.2...aws-amplify-react-native@1.0.5-unstable.3) (2018-07-31) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.5-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.1...aws-amplify-react-native@1.0.5-unstable.2) (2018-07-31) - - +## [1.0.5-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.1...aws-amplify-react-native@1.0.5-unstable.2) (2018-07-31) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.0...aws-amplify-react-native@1.0.5-unstable.1) (2018-07-30) - - +## [1.0.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.5-unstable.0...aws-amplify-react-native@1.0.5-unstable.1) (2018-07-30) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.4...aws-amplify-react-native@1.0.5-unstable.0) (2018-07-30) - - +## [1.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.4...aws-amplify-react-native@1.0.5-unstable.0) (2018-07-30) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.4-unstable.1...aws-amplify-react-native@1.0.4) (2018-07-28) - - +## [1.0.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.4-unstable.1...aws-amplify-react-native@1.0.4) (2018-07-28) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.4-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.4-unstable.0...aws-amplify-react-native@1.0.4-unstable.1) (2018-07-28) - - +## [1.0.4-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.4-unstable.0...aws-amplify-react-native@1.0.4-unstable.1) (2018-07-28) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.14...aws-amplify-react-native@1.0.4-unstable.0) (2018-07-27) - - +## [1.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.14...aws-amplify-react-native@1.0.4-unstable.0) (2018-07-27) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.14...aws-amplify-react-native@1.0.3-unstable.15) (2018-07-27) - - +## [1.0.3-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.14...aws-amplify-react-native@1.0.3-unstable.15) (2018-07-27) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.13...aws-amplify-react-native@1.0.3-unstable.14) (2018-07-27) - - +## [1.0.3-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.13...aws-amplify-react-native@1.0.3-unstable.14) (2018-07-27) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.12...aws-amplify-react-native@1.0.3-unstable.13) (2018-07-26) - - +## [1.0.3-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.12...aws-amplify-react-native@1.0.3-unstable.13) (2018-07-26) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.11...aws-amplify-react-native@1.0.3-unstable.12) (2018-07-26) +## [1.0.3-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.11...aws-amplify-react-native@1.0.3-unstable.12) (2018-07-26) ### Bug Fixes -* **@aws-amplify/auth:** currentAuthenticatedUser throws error when the user is disabled/deleted ([1b09e2f](https://github.com/aws/aws-amplify/commit/1b09e2f)) - - - +- **@aws-amplify/auth:** currentAuthenticatedUser throws error when the user is disabled/deleted ([1b09e2f](https://github.com/aws/aws-amplify/commit/1b09e2f)) -## [1.0.3-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.10...aws-amplify-react-native@1.0.3-unstable.11) (2018-07-26) - - +## [1.0.3-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.10...aws-amplify-react-native@1.0.3-unstable.11) (2018-07-26) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.9...aws-amplify-react-native@1.0.3-unstable.10) (2018-07-26) - - +## [1.0.3-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.9...aws-amplify-react-native@1.0.3-unstable.10) (2018-07-26) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.8...aws-amplify-react-native@1.0.3-unstable.9) (2018-07-25) - - +## [1.0.3-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.8...aws-amplify-react-native@1.0.3-unstable.9) (2018-07-25) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.7...aws-amplify-react-native@1.0.3-unstable.8) (2018-07-25) - - +## [1.0.3-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.7...aws-amplify-react-native@1.0.3-unstable.8) (2018-07-25) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.6...aws-amplify-react-native@1.0.3-unstable.7) (2018-07-25) - - +## [1.0.3-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.6...aws-amplify-react-native@1.0.3-unstable.7) (2018-07-25) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.5...aws-amplify-react-native@1.0.3-unstable.6) (2018-07-24) - - +## [1.0.3-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.5...aws-amplify-react-native@1.0.3-unstable.6) (2018-07-24) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.4...aws-amplify-react-native@1.0.3-unstable.5) (2018-07-23) - - +## [1.0.3-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.4...aws-amplify-react-native@1.0.3-unstable.5) (2018-07-23) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.3...aws-amplify-react-native@1.0.3-unstable.4) (2018-07-23) - - +## [1.0.3-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.3...aws-amplify-react-native@1.0.3-unstable.4) (2018-07-23) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.2...aws-amplify-react-native@1.0.3-unstable.3) (2018-07-23) - - +## [1.0.3-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.2...aws-amplify-react-native@1.0.3-unstable.3) (2018-07-23) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.1...aws-amplify-react-native@1.0.3-unstable.2) (2018-07-20) - - +## [1.0.3-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.1...aws-amplify-react-native@1.0.3-unstable.2) (2018-07-20) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.0...aws-amplify-react-native@1.0.3-unstable.1) (2018-07-20) - - +## [1.0.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.3-unstable.0...aws-amplify-react-native@1.0.3-unstable.1) (2018-07-20) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.2...aws-amplify-react-native@1.0.3-unstable.0) (2018-07-20) - - +## [1.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.2...aws-amplify-react-native@1.0.3-unstable.0) (2018-07-20) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.2-unstable.1...aws-amplify-react-native@1.0.2) (2018-07-19) - - +## [1.0.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.2-unstable.1...aws-amplify-react-native@1.0.2) (2018-07-19) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.2-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1...aws-amplify-react-native@1.0.2-unstable.1) (2018-07-19) - - +## [1.0.2-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1...aws-amplify-react-native@1.0.2-unstable.1) (2018-07-19) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1...aws-amplify-react-native@1.0.2-unstable.0) (2018-07-19) - - +## [1.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1...aws-amplify-react-native@1.0.2-unstable.0) (2018-07-19) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1-unstable.4...aws-amplify-react-native@1.0.1) (2018-07-18) - - +## [1.0.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1-unstable.4...aws-amplify-react-native@1.0.1) (2018-07-18) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.1-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1-unstable.3...aws-amplify-react-native@1.0.1-unstable.4) (2018-07-18) - - +## [1.0.1-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1-unstable.3...aws-amplify-react-native@1.0.1-unstable.4) (2018-07-18) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.1-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1-unstable.2...aws-amplify-react-native@1.0.1-unstable.3) (2018-07-18) - - +## [1.0.1-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1-unstable.2...aws-amplify-react-native@1.0.1-unstable.3) (2018-07-18) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1-unstable.1...aws-amplify-react-native@1.0.1-unstable.2) (2018-07-18) - - +## [1.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1-unstable.1...aws-amplify-react-native@1.0.1-unstable.2) (2018-07-18) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1...aws-amplify-react-native@1.0.1-unstable.1) (2018-07-18) - - +## [1.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1...aws-amplify-react-native@1.0.1-unstable.1) (2018-07-18) **Note:** Version bump only for package aws-amplify-react-native -## [1.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1...aws-amplify-react-native@1.0.1-unstable.0) (2018-07-18) - - +## [1.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@1.0.1...aws-amplify-react-native@1.0.1-unstable.0) (2018-07-18) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.20-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.20-unstable.0...aws-amplify-react-native@0.2.20-unstable.1) (2018-07-03) - - +## [0.2.20-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.20-unstable.0...aws-amplify-react-native@0.2.20-unstable.1) (2018-07-03) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.20-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19...aws-amplify-react-native@0.2.20-unstable.0) (2018-07-02) - - +## [0.2.20-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19...aws-amplify-react-native@0.2.20-unstable.0) (2018-07-02) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.19](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.5...aws-amplify-react-native@0.2.19) (2018-06-29) - - +## [0.2.19](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.5...aws-amplify-react-native@0.2.19) (2018-06-29) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.19-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.4...aws-amplify-react-native@0.2.19-unstable.5) (2018-06-29) - - +## [0.2.19-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.4...aws-amplify-react-native@0.2.19-unstable.5) (2018-06-29) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.19-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.3...aws-amplify-react-native@0.2.19-unstable.4) (2018-06-29) - - +## [0.2.19-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.3...aws-amplify-react-native@0.2.19-unstable.4) (2018-06-29) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.19-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.2...aws-amplify-react-native@0.2.19-unstable.3) (2018-06-28) - - +## [0.2.19-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.2...aws-amplify-react-native@0.2.19-unstable.3) (2018-06-28) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.19-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.1...aws-amplify-react-native@0.2.19-unstable.2) (2018-06-27) - - +## [0.2.19-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.1...aws-amplify-react-native@0.2.19-unstable.2) (2018-06-27) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.19-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.0...aws-amplify-react-native@0.2.19-unstable.1) (2018-06-27) - - +## [0.2.19-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.19-unstable.0...aws-amplify-react-native@0.2.19-unstable.1) (2018-06-27) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.19-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.18-unstable.2...aws-amplify-react-native@0.2.19-unstable.0) (2018-06-27) +## [0.2.19-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.18-unstable.2...aws-amplify-react-native@0.2.19-unstable.0) (2018-06-27) ### Features -* **interactions:** Interactions UI components for react and react native ([#1105](https://github.com/aws/aws-amplify/issues/1105)) ([57de248](https://github.com/aws/aws-amplify/commit/57de248)) - - - +- **interactions:** Interactions UI components for react and react native ([#1105](https://github.com/aws/aws-amplify/issues/1105)) ([57de248](https://github.com/aws/aws-amplify/commit/57de248)) -## [0.2.18](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.18-unstable.2...aws-amplify-react-native@0.2.18) (2018-06-27) +## [0.2.18](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.18-unstable.2...aws-amplify-react-native@0.2.18) (2018-06-27) ### Features -* **interactions:** Interactions UI components for react and react native ([#1105](https://github.com/aws/aws-amplify/issues/1105)) ([57de248](https://github.com/aws/aws-amplify/commit/57de248)) - - - +- **interactions:** Interactions UI components for react and react native ([#1105](https://github.com/aws/aws-amplify/issues/1105)) ([57de248](https://github.com/aws/aws-amplify/commit/57de248)) -## [0.2.18-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.18-unstable.1...aws-amplify-react-native@0.2.18-unstable.2) (2018-06-26) +## [0.2.18-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.18-unstable.1...aws-amplify-react-native@0.2.18-unstable.2) (2018-06-26) ### Bug Fixes -* **integration tests:** CircleCI workflows and Cypress integration testing ([#1071](https://github.com/aws/aws-amplify/issues/1071)) ([bfa4776](https://github.com/aws/aws-amplify/commit/bfa4776)) - - - +- **integration tests:** CircleCI workflows and Cypress integration testing ([#1071](https://github.com/aws/aws-amplify/issues/1071)) ([bfa4776](https://github.com/aws/aws-amplify/commit/bfa4776)) -## [0.2.18-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.18-unstable.0...aws-amplify-react-native@0.2.18-unstable.1) (2018-06-22) +## [0.2.18-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.18-unstable.0...aws-amplify-react-native@0.2.18-unstable.1) (2018-06-22) ### Bug Fixes -* **aws-amplify-react-native:** firebase-messaging and firebase-core version update ([a1031ec](https://github.com/aws/aws-amplify/commit/a1031ec)) - - - +- **aws-amplify-react-native:** firebase-messaging and firebase-core version update ([a1031ec](https://github.com/aws/aws-amplify/commit/a1031ec)) -## [0.2.18-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.17...aws-amplify-react-native@0.2.18-unstable.0) (2018-06-22) - - +## [0.2.18-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.17...aws-amplify-react-native@0.2.18-unstable.0) (2018-06-22) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.16-unstable.3...aws-amplify-react-native@0.2.17) (2018-06-21) - - +## [0.2.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.16-unstable.3...aws-amplify-react-native@0.2.17) (2018-06-21) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.29...aws-amplify-react-native@0.2.16) (2018-06-20) - -## [0.2.16-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.16-unstable.2...aws-amplify-react-native@0.2.16-unstable.3) (2018-06-21) +## [0.2.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.29...aws-amplify-react-native@0.2.16) (2018-06-20) + +## [0.2.16-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.16-unstable.2...aws-amplify-react-native@0.2.16-unstable.3) (2018-06-21) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.16-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.16-unstable.1...aws-amplify-react-native@0.2.16-unstable.2) (2018-06-21) - - +## [0.2.16-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.16-unstable.1...aws-amplify-react-native@0.2.16-unstable.2) (2018-06-21) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.16-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.16-unstable.0...aws-amplify-react-native@0.2.16-unstable.1) (2018-06-20) - - +## [0.2.16-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.16-unstable.0...aws-amplify-react-native@0.2.16-unstable.1) (2018-06-20) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.16-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.29...aws-amplify-react-native@0.2.16-unstable.0) (2018-06-20) +## [0.2.16-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.29...aws-amplify-react-native@0.2.16-unstable.0) (2018-06-20) ### Bug Fixes -* **pushnotification:** revert change in pr 952 ([b8d167c](https://github.com/aws/aws-amplify/commit/b8d167c)) -* **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) - - - +- **pushnotification:** revert change in pr 952 ([b8d167c](https://github.com/aws/aws-amplify/commit/b8d167c)) +- **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) -## [0.2.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.15...aws-amplify-react-native@0.2.15) (2018-06-04) - -## [0.2.13-unstable.29](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.28...aws-amplify-react-native@0.2.13-unstable.29) (2018-06-19) +## [0.2.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.15...aws-amplify-react-native@0.2.15) (2018-06-04) + +## [0.2.13-unstable.29](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.28...aws-amplify-react-native@0.2.13-unstable.29) (2018-06-19) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.28](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.27...aws-amplify-react-native@0.2.13-unstable.28) (2018-06-18) - - +## [0.2.13-unstable.28](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.27...aws-amplify-react-native@0.2.13-unstable.28) (2018-06-18) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.27](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.26...aws-amplify-react-native@0.2.13-unstable.27) (2018-06-18) - - +## [0.2.13-unstable.27](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.26...aws-amplify-react-native@0.2.13-unstable.27) (2018-06-18) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.26](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.25...aws-amplify-react-native@0.2.13-unstable.26) (2018-06-16) - - +## [0.2.13-unstable.26](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.25...aws-amplify-react-native@0.2.13-unstable.26) (2018-06-16) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.25](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.24...aws-amplify-react-native@0.2.13-unstable.25) (2018-06-13) - - +## [0.2.13-unstable.25](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.24...aws-amplify-react-native@0.2.13-unstable.25) (2018-06-13) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.24](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.23...aws-amplify-react-native@0.2.13-unstable.24) (2018-06-13) - - +## [0.2.13-unstable.24](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.23...aws-amplify-react-native@0.2.13-unstable.24) (2018-06-13) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.23](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.22...aws-amplify-react-native@0.2.13-unstable.23) (2018-06-12) - - +## [0.2.13-unstable.23](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.22...aws-amplify-react-native@0.2.13-unstable.23) (2018-06-12) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.22](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.21...aws-amplify-react-native@0.2.13-unstable.22) (2018-06-11) - - +## [0.2.13-unstable.22](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.21...aws-amplify-react-native@0.2.13-unstable.22) (2018-06-11) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.21](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.20...aws-amplify-react-native@0.2.13-unstable.21) (2018-06-08) - - +## [0.2.13-unstable.21](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.20...aws-amplify-react-native@0.2.13-unstable.21) (2018-06-08) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.20](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.19...aws-amplify-react-native@0.2.13-unstable.20) (2018-06-08) - - +## [0.2.13-unstable.20](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.19...aws-amplify-react-native@0.2.13-unstable.20) (2018-06-08) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.19](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.18...aws-amplify-react-native@0.2.13-unstable.19) (2018-06-07) - - +## [0.2.13-unstable.19](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.18...aws-amplify-react-native@0.2.13-unstable.19) (2018-06-07) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.18](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.17...aws-amplify-react-native@0.2.13-unstable.18) (2018-06-06) - - +## [0.2.13-unstable.18](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.17...aws-amplify-react-native@0.2.13-unstable.18) (2018-06-06) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.16...aws-amplify-react-native@0.2.13-unstable.17) (2018-06-05) - - +## [0.2.13-unstable.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.16...aws-amplify-react-native@0.2.13-unstable.17) (2018-06-05) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.15...aws-amplify-react-native@0.2.13-unstable.16) (2018-06-04) - - +## [0.2.13-unstable.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.15...aws-amplify-react-native@0.2.13-unstable.16) (2018-06-04) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.14...aws-amplify-react-native@0.2.13-unstable.15) (2018-06-04) +## [0.2.13-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.14...aws-amplify-react-native@0.2.13-unstable.15) (2018-06-04) ### Bug Fixes -* **pushnotification:** revert change in pr 952 ([b8d167c](https://github.com/aws/aws-amplify/commit/b8d167c)) -* **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) - - - +- **pushnotification:** revert change in pr 952 ([b8d167c](https://github.com/aws/aws-amplify/commit/b8d167c)) +- **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) -## [0.2.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13...aws-amplify-react-native@0.2.14) (2018-06-02) - - +## [0.2.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13...aws-amplify-react-native@0.2.14) (2018-06-02) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.12...aws-amplify-react-native@0.2.13) (2018-06-01) - -## [0.2.13-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.12...aws-amplify-react-native@0.2.13-unstable.13) (2018-06-02) +## [0.2.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.12...aws-amplify-react-native@0.2.13) (2018-06-01) + +## [0.2.13-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.12...aws-amplify-react-native@0.2.13-unstable.13) (2018-06-02) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.11...aws-amplify-react-native@0.2.13-unstable.12) (2018-06-01) - - +## [0.2.13-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.11...aws-amplify-react-native@0.2.13-unstable.12) (2018-06-01) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.10...aws-amplify-react-native@0.2.13-unstable.11) (2018-06-01) - - +## [0.2.13-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.10...aws-amplify-react-native@0.2.13-unstable.11) (2018-06-01) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.9...aws-amplify-react-native@0.2.13-unstable.10) (2018-06-01) - - +## [0.2.13-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.9...aws-amplify-react-native@0.2.13-unstable.10) (2018-06-01) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.8...aws-amplify-react-native@0.2.13-unstable.9) (2018-05-31) - - +## [0.2.13-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.8...aws-amplify-react-native@0.2.13-unstable.9) (2018-05-31) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.5...aws-amplify-react-native@0.2.13-unstable.8) (2018-05-31) - - +## [0.2.13-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.5...aws-amplify-react-native@0.2.13-unstable.8) (2018-05-31) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.4...aws-amplify-react-native@0.2.13-unstable.5) (2018-05-31) - - +## [0.2.13-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.4...aws-amplify-react-native@0.2.13-unstable.5) (2018-05-31) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.3...aws-amplify-react-native@0.2.13-unstable.4) (2018-05-31) - - +## [0.2.13-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.3...aws-amplify-react-native@0.2.13-unstable.4) (2018-05-31) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.2...aws-amplify-react-native@0.2.13-unstable.3) (2018-05-30) - - +## [0.2.13-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.2...aws-amplify-react-native@0.2.13-unstable.3) (2018-05-30) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.1...aws-amplify-react-native@0.2.13-unstable.2) (2018-05-29) - - +## [0.2.13-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.1...aws-amplify-react-native@0.2.13-unstable.2) (2018-05-29) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.0...aws-amplify-react-native@0.2.13-unstable.1) (2018-05-29) - - +## [0.2.13-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.13-unstable.0...aws-amplify-react-native@0.2.13-unstable.1) (2018-05-29) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.13-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.17...aws-amplify-react-native@0.2.13-unstable.0) (2018-05-29) - - +## [0.2.13-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.17...aws-amplify-react-native@0.2.13-unstable.0) (2018-05-29) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.16...aws-amplify-react-native@0.2.12-unstable.17) (2018-05-24) - - +## [0.2.12-unstable.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.16...aws-amplify-react-native@0.2.12-unstable.17) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.15...aws-amplify-react-native@0.2.12-unstable.16) (2018-05-24) - - +## [0.2.12-unstable.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.15...aws-amplify-react-native@0.2.12-unstable.16) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.14...aws-amplify-react-native@0.2.12-unstable.15) (2018-05-24) - - +## [0.2.12-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.14...aws-amplify-react-native@0.2.12-unstable.15) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.13...aws-amplify-react-native@0.2.12-unstable.14) (2018-05-24) - - +## [0.2.12-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.13...aws-amplify-react-native@0.2.12-unstable.14) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.12...aws-amplify-react-native@0.2.12-unstable.13) (2018-05-24) - - +## [0.2.12-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.12...aws-amplify-react-native@0.2.12-unstable.13) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.11...aws-amplify-react-native@0.2.12-unstable.12) (2018-05-24) - - +## [0.2.12-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.11...aws-amplify-react-native@0.2.12-unstable.12) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.10...aws-amplify-react-native@0.2.12-unstable.11) (2018-05-24) - - +## [0.2.12-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.10...aws-amplify-react-native@0.2.12-unstable.11) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.11...aws-amplify-react-native@0.2.12-unstable.10) (2018-05-24) - - +## [0.2.12-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.11...aws-amplify-react-native@0.2.12-unstable.10) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.8...aws-amplify-react-native@0.2.12-unstable.9) (2018-05-24) - - +## [0.2.12-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.8...aws-amplify-react-native@0.2.12-unstable.9) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.7...aws-amplify-react-native@0.2.12-unstable.8) (2018-05-24) - - +## [0.2.12-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.7...aws-amplify-react-native@0.2.12-unstable.8) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.6...aws-amplify-react-native@0.2.12-unstable.7) (2018-05-24) - - +## [0.2.12-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.6...aws-amplify-react-native@0.2.12-unstable.7) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.5...aws-amplify-react-native@0.2.12-unstable.6) (2018-05-24) - - +## [0.2.12-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.5...aws-amplify-react-native@0.2.12-unstable.6) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.4...aws-amplify-react-native@0.2.12-unstable.5) (2018-05-24) - - +## [0.2.12-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.4...aws-amplify-react-native@0.2.12-unstable.5) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.3...aws-amplify-react-native@0.2.12-unstable.4) (2018-05-24) - - +## [0.2.12-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.3...aws-amplify-react-native@0.2.12-unstable.4) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.2...aws-amplify-react-native@0.2.12-unstable.3) (2018-05-24) - - +## [0.2.12-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.2...aws-amplify-react-native@0.2.12-unstable.3) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.1...aws-amplify-react-native@0.2.12-unstable.2) (2018-05-24) - - +## [0.2.12-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.1...aws-amplify-react-native@0.2.12-unstable.2) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.0...aws-amplify-react-native@0.2.12-unstable.1) (2018-05-24) - - +## [0.2.12-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.12-unstable.0...aws-amplify-react-native@0.2.12-unstable.1) (2018-05-24) **Note:** Version bump only for package aws-amplify-react-native -## [0.2.12-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.11...aws-amplify-react-native@0.2.12-unstable.0) (2018-05-23) - - +## [0.2.12-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react-native@0.2.11...aws-amplify-react-native@0.2.12-unstable.0) (2018-05-23) **Note:** Version bump only for package aws-amplify-react-native diff --git a/packages/aws-amplify-react-native/docs/scripts/linenumber.js b/packages/aws-amplify-react-native/docs/scripts/linenumber.js index 8d52f7eafdb..034fc4142b7 100644 --- a/packages/aws-amplify-react-native/docs/scripts/linenumber.js +++ b/packages/aws-amplify-react-native/docs/scripts/linenumber.js @@ -1,25 +1,25 @@ /*global document */ (function() { - var source = document.getElementsByClassName('prettyprint source linenums'); - var i = 0; - var lineNumber = 0; - var lineId; - var lines; - var totalLines; - var anchorHash; + var source = document.getElementsByClassName('prettyprint source linenums'); + var i = 0; + var lineNumber = 0; + var lineId; + var lines; + var totalLines; + var anchorHash; - if (source && source[0]) { - anchorHash = document.location.hash.substring(1); - lines = source[0].getElementsByTagName('li'); - totalLines = lines.length; + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; - for (; i < totalLines; i++) { - lineNumber++; - lineId = 'line' + lineNumber; - lines[i].id = lineId; - if (lineId === anchorHash) { - lines[i].className += ' selected'; - } - } - } + for (; i < totalLines; i++) { + lineNumber++; + lineId = 'line' + lineNumber; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } + } })(); diff --git a/packages/aws-amplify-react-native/docs/scripts/prettify/lang-css.js b/packages/aws-amplify-react-native/docs/scripts/prettify/lang-css.js index 041e1f59067..a49667a3d2d 100644 --- a/packages/aws-amplify-react-native/docs/scripts/prettify/lang-css.js +++ b/packages/aws-amplify-react-native/docs/scripts/prettify/lang-css.js @@ -1,2 +1,36 @@ -PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", -/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); +PR.registerLangHandler( + PR.createSimpleLexer( + [['pln', /^[\t\n\f\r ]+/, null, ' \t\r\n ']], + [ + ['str', /^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/, null], + ['str', /^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/, null], + ['lang-css-str', /^url\(([^"')]*)\)/i], + [ + 'kwd', + /^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i, + null, + ], + [ + 'lang-css-kw', + /^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i, + ], + ['com', /^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//], + ['com', /^(?:<\!--|--\>)/], + ['lit', /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], + ['lit', /^#[\da-f]{3,6}/i], + ['pln', /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i], + ['pun', /^[^\s\w"']+/], + ] + ), + ['css'] +); +PR.registerLangHandler( + PR.createSimpleLexer( + [], + [['kwd', /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]] + ), + ['css-kw'] +); +PR.registerLangHandler(PR.createSimpleLexer([], [['str', /^[^"')]+/]]), [ + 'css-str', +]); diff --git a/packages/aws-amplify-react-native/docs/scripts/prettify/prettify.js b/packages/aws-amplify-react-native/docs/scripts/prettify/prettify.js index eef5ad7e6a0..ab1514dd933 100644 --- a/packages/aws-amplify-react-native/docs/scripts/prettify/prettify.js +++ b/packages/aws-amplify-react-native/docs/scripts/prettify/prettify.js @@ -1,28 +1,739 @@ -var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; -(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= -[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), -l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, -q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, -q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, -"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), -a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} -for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], -"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], -H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], -J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ -I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), -["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", -/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), -["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", -hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= -!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p 122 || + (d < 65 || + j > 90 || + b.push([Math.max(65, j) | 32, Math.min(d, 90) | 32]), + d < 97 || + j > 122 || + b.push([Math.max(97, j) & -33, Math.min(d, 122) & -33])); + } + } + b.sort(function(a, f) { + return a[0] - f[0] || f[1] - a[1]; + }); + f = []; + j = [NaN, NaN]; + for (c = 0; c < b.length; ++c) + (i = b[c]), + i[0] <= j[1] + 1 ? (j[1] = Math.max(j[1], i[1])) : f.push((j = i)); + b = ['[']; + o && b.push('^'); + b.push.apply(b, a); + for (c = 0; c < f.length; ++c) + (i = f[c]), + b.push(e(i[0])), + i[1] > i[0] && (i[1] + 1 > i[0] && b.push('-'), b.push(e(i[1]))); + b.push(']'); + return b.join(''); + } + function y(a) { + for ( + var f = a.source.match( + /\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g + ), + b = f.length, + d = [], + c = 0, + i = 0; + c < b; + ++c + ) { + var j = f[c]; + j === '(' + ? ++i + : '\\' === j.charAt(0) && + (j = +j.substring(1)) && + j <= i && + (d[j] = -1); + } + for (c = 1; c < d.length; ++c) -1 === d[c] && (d[c] = ++t); + for (i = c = 0; c < b; ++c) + (j = f[c]), + j === '(' + ? (++i, d[i] === void 0 && (f[c] = '(?:')) + : '\\' === j.charAt(0) && + (j = +j.substring(1)) && + j <= i && + (f[c] = '\\' + d[i]); + for (i = c = 0; c < b; ++c) + '^' === f[c] && '^' !== f[c + 1] && (f[c] = ''); + if (a.ignoreCase && s) + for (c = 0; c < b; ++c) + (j = f[c]), + (a = j.charAt(0)), + j.length >= 2 && a === '[' + ? (f[c] = h(j)) + : a !== '\\' && + (f[c] = j.replace(/[A-Za-z]/g, function(a) { + a = a.charCodeAt(0); + return '[' + String.fromCharCode(a & -33, a | 32) + ']'; + })); + return f.join(''); + } + for (var t = 0, s = !1, l = !1, p = 0, d = a.length; p < d; ++p) { + var g = a[p]; + if (g.ignoreCase) l = !0; + else if ( + /[a-z]/i.test( + g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi, '') + ) + ) { + s = !0; + l = !1; + break; + } + } + for ( + var r = { b: 8, t: 9, n: 10, v: 11, f: 12, r: 13 }, + n = [], + p = 0, + d = a.length; + p < d; + ++p + ) { + g = a[p]; + if (g.global || g.multiline) throw Error('' + g); + n.push('(?:' + y(g) + ')'); + } + return RegExp(n.join('|'), l ? 'gi' : 'g'); + } + function M(a) { + function m(a) { + switch (a.nodeType) { + case 1: + if (e.test(a.className)) break; + for (var g = a.firstChild; g; g = g.nextSibling) m(g); + g = a.nodeName; + if ('BR' === g || 'LI' === g) + (h[s] = '\n'), (t[s << 1] = y++), (t[(s++ << 1) | 1] = a); + break; + case 3: + case 4: + (g = a.nodeValue), + g.length && + ((g = p + ? g.replace(/\r\n?/g, '\n') + : g.replace(/[\t\n\r ]+/g, ' ')), + (h[s] = g), + (t[s << 1] = y), + (y += g.length), + (t[(s++ << 1) | 1] = a)); + } + } + var e = /(?:^|\s)nocode(?:\s|$)/, + h = [], + y = 0, + t = [], + s = 0, + l; + a.currentStyle + ? (l = a.currentStyle.whiteSpace) + : window.getComputedStyle && + (l = document.defaultView + .getComputedStyle(a, q) + .getPropertyValue('white-space')); + var p = l && 'pre' === l.substring(0, 3); + m(a); + return { a: h.join('').replace(/\n$/, ''), c: t }; + } + function B(a, m, e, h) { + m && ((a = { a: m, d: a }), e(a), h.push.apply(h, a.e)); + } + function x(a, m) { + function e(a) { + for ( + var l = a.d, + p = [l, 'pln'], + d = 0, + g = a.a.match(y) || [], + r = {}, + n = 0, + z = g.length; + n < z; + ++n + ) { + var f = g[n], + b = r[f], + o = void 0, + c; + if (typeof b === 'string') c = !1; + else { + var i = h[f.charAt(0)]; + if (i) (o = f.match(i[1])), (b = i[0]); + else { + for (c = 0; c < t; ++c) + if (((i = m[c]), (o = f.match(i[1])))) { + b = i[0]; + break; + } + o || (b = 'pln'); + } + if ( + (c = b.length >= 5 && 'lang-' === b.substring(0, 5)) && + !(o && typeof o[1] === 'string') + ) + (c = !1), (b = 'src'); + c || (r[f] = b); + } + i = d; + d += f.length; + if (c) { + c = o[1]; + var j = f.indexOf(c), + k = j + c.length; + o[2] && ((k = f.length - o[2].length), (j = k - c.length)); + b = b.substring(5); + B(l + i, f.substring(0, j), e, p); + B(l + i + j, c, C(b, c), p); + B(l + i + k, f.substring(k), e, p); + } else p.push(l + i, b); + } + a.e = p; + } + var h = {}, + y; + (function() { + for ( + var e = a.concat(m), l = [], p = {}, d = 0, g = e.length; + d < g; + ++d + ) { + var r = e[d], + n = r[3]; + if (n) for (var k = n.length; --k >= 0; ) h[n.charAt(k)] = r; + r = r[1]; + n = '' + r; + p.hasOwnProperty(n) || (l.push(r), (p[n] = q)); + } + l.push(/[\S\s]/); + y = L(l); + })(); + var t = m.length; + return e; + } + function u(a) { + var m = [], + e = []; + a.tripleQuotedStrings + ? m.push([ + 'str', + /^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/, + q, + '\'"', + ]) + : a.multiLineStrings + ? m.push([ + 'str', + /^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, + q, + '\'"`', + ]) + : m.push([ + 'str', + /^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/, + q, + '"\'', + ]); + a.verbatimStrings && e.push(['str', /^@"(?:[^"]|"")*(?:"|$)/, q]); + var h = a.hashComments; + h && + (a.cStyleComments + ? (h > 1 + ? m.push(['com', /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, q, '#']) + : m.push([ + 'com', + /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/, + q, + '#', + ]), + e.push([ + 'str', + /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, + q, + ])) + : m.push(['com', /^#[^\n\r]*/, q, '#'])); + a.cStyleComments && + (e.push(['com', /^\/\/[^\n\r]*/, q]), + e.push(['com', /^\/\*[\S\s]*?(?:\*\/|$)/, q])); + a.regexLiterals && + e.push([ + 'lang-regex', + /^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/, + ]); + (h = a.types) && e.push(['typ', h]); + a = ('' + a.keywords).replace(/^ | $/g, ''); + a.length && + e.push(['kwd', RegExp('^(?:' + a.replace(/[\s,]+/g, '|') + ')\\b'), q]); + m.push(['pln', /^\s+/, q, ' \r\n\t\xa0']); + e.push( + ['lit', /^@[$_a-z][\w$@]*/i, q], + ['typ', /^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/, q], + ['pln', /^[$_a-z][\w$@]*/i, q], + [ + 'lit', + /^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i, + q, + '0123456789', + ], + ['pln', /^\\[\S\s]?/, q], + ['pun', /^.[^\s\w"-$'./@\\`]*/, q] + ); + return x(m, e); + } + function D(a, m) { + function e(a) { + switch (a.nodeType) { + case 1: + if (k.test(a.className)) break; + if ('BR' === a.nodeName) + h(a), a.parentNode && a.parentNode.removeChild(a); + else for (a = a.firstChild; a; a = a.nextSibling) e(a); + break; + case 3: + case 4: + if (p) { + var b = a.nodeValue, + d = b.match(t); + if (d) { + var c = b.substring(0, d.index); + a.nodeValue = c; + (b = b.substring(d.index + d[0].length)) && + a.parentNode.insertBefore(s.createTextNode(b), a.nextSibling); + h(a); + c || a.parentNode.removeChild(a); + } + } + } + } + function h(a) { + function b(a, d) { + var e = d ? a.cloneNode(!1) : a, + f = a.parentNode; + if (f) { + var f = b(f, 1), + g = a.nextSibling; + f.appendChild(e); + for (var h = g; h; h = g) (g = h.nextSibling), f.appendChild(h); + } + return e; + } + for (; !a.nextSibling; ) if (((a = a.parentNode), !a)) return; + for ( + var a = b(a.nextSibling, 0), e; + (e = a.parentNode) && e.nodeType === 1; + + ) + a = e; + d.push(a); + } + var k = /(?:^|\s)nocode(?:\s|$)/, + t = /\r\n?|\n/, + s = a.ownerDocument, + l; + a.currentStyle + ? (l = a.currentStyle.whiteSpace) + : window.getComputedStyle && + (l = s.defaultView + .getComputedStyle(a, q) + .getPropertyValue('white-space')); + var p = l && 'pre' === l.substring(0, 3); + for (l = s.createElement('LI'); a.firstChild; ) l.appendChild(a.firstChild); + for (var d = [l], g = 0; g < d.length; ++g) e(d[g]); + m === (m | 0) && d[0].setAttribute('value', m); + var r = s.createElement('OL'); + r.className = 'linenums'; + for (var n = Math.max(0, (m - 1) | 0) || 0, g = 0, z = d.length; g < z; ++g) + (l = d[g]), + (l.className = 'L' + ((g + n) % 10)), + l.firstChild || l.appendChild(s.createTextNode('\xa0')), + r.appendChild(l); + a.appendChild(r); + } + function k(a, m) { + for (var e = m.length; --e >= 0; ) { + var h = m[e]; + A.hasOwnProperty(h) + ? window.console && + console.warn('cannot override language handler %s', h) + : (A[h] = a); + } + } + function C(a, m) { + if (!a || !A.hasOwnProperty(a)) + a = /^\s*= o && (h += 2); + e >= c && (a += 2); + } + } catch (w) { + 'console' in window && console.log(w && w.stack ? w.stack : w); + } + } + var v = ['break,continue,do,else,for,if,return,while'], + w = [ + [ + v, + 'auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile', + ], + 'catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof', + ], + F = [ + w, + 'alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where', + ], + G = [ + w, + 'abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient', + ], + H = [ + G, + 'as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var', + ], + w = [ + w, + 'debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN', + ], + I = [ + v, + 'and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None', + ], + J = [ + v, + 'alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END', + ], + v = [v, 'case,done,elif,esac,eval,fi,function,in,local,set,then,until'], + K = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/, + N = /\S/, + O = u({ + keywords: [ + F, + H, + w, + 'caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END' + + I, + J, + v, + ], + hashComments: !0, + cStyleComments: !0, + multiLineStrings: !0, + regexLiterals: !0, + }), + A = {}; + k(O, ['default-code']); + k( + x( + [], + [ + ['pln', /^[^]*(?:>|$)/], + ['com', /^<\!--[\S\s]*?(?:--\>|$)/], + ['lang-', /^<\?([\S\s]+?)(?:\?>|$)/], + ['lang-', /^<%([\S\s]+?)(?:%>|$)/], + ['pun', /^(?:<[%?]|[%?]>)/], + ['lang-', /^]*>([\S\s]+?)<\/xmp\b[^>]*>/i], + ['lang-js', /^]*>([\S\s]*?)(<\/script\b[^>]*>)/i], + ['lang-css', /^]*>([\S\s]*?)(<\/style\b[^>]*>)/i], + ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i], + ] + ), + ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl'] + ); + k( + x( + [ + ['pln', /^\s+/, q, ' \t\r\n'], + ['atv', /^(?:"[^"]*"?|'[^']*'?)/, q, '"\''], + ], + [ + ['tag', /^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i], + ['atn', /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], + ['lang-uq.val', /^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/], + ['pun', /^[/<->]+/], + ['lang-js', /^on\w+\s*=\s*"([^"]+)"/i], + ['lang-js', /^on\w+\s*=\s*'([^']+)'/i], + ['lang-js', /^on\w+\s*=\s*([^\s"'>]+)/i], + ['lang-css', /^style\s*=\s*"([^"]+)"/i], + ['lang-css', /^style\s*=\s*'([^']+)'/i], + ['lang-css', /^style\s*=\s*([^\s"'>]+)/i], + ] + ), + ['in.tag'] + ); + k(x([], [['atv', /^[\S\s]+/]]), ['uq.val']); + k(u({ keywords: F, hashComments: !0, cStyleComments: !0, types: K }), [ + 'c', + 'cc', + 'cpp', + 'cxx', + 'cyc', + 'm', + ]); + k(u({ keywords: 'null,true,false' }), ['json']); + k( + u({ + keywords: H, + hashComments: !0, + cStyleComments: !0, + verbatimStrings: !0, + types: K, + }), + ['cs'] + ); + k(u({ keywords: G, cStyleComments: !0 }), ['java']); + k(u({ keywords: v, hashComments: !0, multiLineStrings: !0 }), [ + 'bsh', + 'csh', + 'sh', + ]); + k( + u({ + keywords: I, + hashComments: !0, + multiLineStrings: !0, + tripleQuotedStrings: !0, + }), + ['cv', 'py'] + ); + k( + u({ + keywords: + 'caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END', + hashComments: !0, + multiLineStrings: !0, + regexLiterals: !0, + }), + ['perl', 'pl', 'pm'] + ); + k( + u({ + keywords: J, + hashComments: !0, + multiLineStrings: !0, + regexLiterals: !0, + }), + ['rb'] + ); + k(u({ keywords: w, cStyleComments: !0, regexLiterals: !0 }), ['js']); + k( + u({ + keywords: + 'all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes', + hashComments: 3, + cStyleComments: !0, + multilineStrings: !0, + tripleQuotedStrings: !0, + regexLiterals: !0, + }), + ['coffee'] + ); + k(x([], [['str', /^[\S\s]+/]]), ['regex']); + window.prettyPrintOne = function(a, m, e) { + var h = document.createElement('PRE'); + h.innerHTML = a; + e && D(h, e); + E({ g: m, i: e, h: h }); + return h.innerHTML; + }; + window.prettyPrint = function(a) { + function m() { + for ( + var e = window.PR_SHOULD_USE_CONTINUATION ? l.now() + 250 : Infinity; + p < h.length && l.now() < e; + p++ + ) { + var n = h[p], + k = n.className; + if (k.indexOf('prettyprint') >= 0) { + var k = k.match(g), + f, + b; + if ((b = !k)) { + b = n; + for (var o = void 0, c = b.firstChild; c; c = c.nextSibling) + var i = c.nodeType, + o = + i === 1 + ? o + ? b + : c + : i === 3 + ? N.test(c.nodeValue) + ? b + : o + : o; + b = (f = o === b ? void 0 : o) && 'CODE' === f.tagName; + } + b && (k = f.className.match(g)); + k && (k = k[1]); + b = !1; + for (o = n.parentNode; o; o = o.parentNode) + if ( + (o.tagName === 'pre' || + o.tagName === 'code' || + o.tagName === 'xmp') && + o.className && + o.className.indexOf('prettyprint') >= 0 + ) { + b = !0; + break; + } + b || + ((b = (b = n.className.match(/\blinenums\b(?::(\d+))?/)) + ? b[1] && b[1].length + ? +b[1] + : !0 + : !1) && D(n, b), + (d = { g: k, h: n, i: b }), + E(d)); + } + } + p < h.length ? setTimeout(m, 250) : a && a(); + } + for ( + var e = [ + document.getElementsByTagName('pre'), + document.getElementsByTagName('code'), + document.getElementsByTagName('xmp'), + ], + h = [], + k = 0; + k < e.length; + ++k + ) + for (var t = 0, s = e[k].length; t < s; ++t) h.push(e[k][t]); + var e = q, + l = Date; + l.now || + (l = { + now: function() { + return +new Date(); + }, + }); + var p = 0, + d, + g = /\blang(?:uage)?-([\w.]+)(?!\S)/; + m(); + }; + window.PR = { + createSimpleLexer: x, + registerLangHandler: k, + sourceDecorator: u, + PR_ATTRIB_NAME: 'atn', + PR_ATTRIB_VALUE: 'atv', + PR_COMMENT: 'com', + PR_DECLARATION: 'dec', + PR_KEYWORD: 'kwd', + PR_LITERAL: 'lit', + PR_NOCODE: 'nocode', + PR_PLAIN: 'pln', + PR_PUNCTUATION: 'pun', + PR_SOURCE: 'src', + PR_STRING: 'str', + PR_TAG: 'tag', + PR_TYPE: 'typ', + }; +})(); diff --git a/packages/aws-amplify-react-native/src/API/GraphQL/Connect.js b/packages/aws-amplify-react-native/src/API/GraphQL/Connect.js index 0bec58fe2a0..328a34ac1fc 100644 --- a/packages/aws-amplify-react-native/src/API/GraphQL/Connect.js +++ b/packages/aws-amplify-react-native/src/API/GraphQL/Connect.js @@ -2,146 +2,160 @@ import 'regenerator-runtime/runtime'; import React, { Component } from 'react'; import { parse } from 'graphql/language/parser'; -import { API } from "aws-amplify"; +import { API } from 'aws-amplify'; const getOperationType = operation => { - const doc = parse(operation); - const { definitions: [{ operation: operationType },] } = doc + const doc = parse(operation); + const { + definitions: [{ operation: operationType }], + } = doc; - return operationType; -} + return operationType; +}; export default class Connect extends Component { - - constructor(props) { - super(props); - - this.state = this.getInitialState(); - this.subSubscription = null; - } - - getInitialState() { - const { query } = this.props; - return { - loading: query && !!query.query, - data: {}, - errors: [], - mutation: () => console.warn('Not implemented'), - }; - } - - getDefaultState() { - return { - loading: false, - data: {}, - errors: [], - mutation: () => console.warn('Not implemented'), - }; - } - - async _fetchData() { - this._unsubscribe(); - this.setState({ loading: true }); - - const { - query: { query, variables = {} } = {}, - mutation: { query: mutation, mutationVariables = {} } = {}, - subscription, - onSubscriptionMsg = (prevData) => prevData, - } = this.props; - - let { data, mutation: mutationProp, errors } = this.getDefaultState(); - - const hasValidQuery = query && getOperationType(query) === 'query'; - const hasValidMutation = mutation && getOperationType(mutation) === 'mutation'; - const hasValidSubscription = subscription && getOperationType(subscription.query) === 'subscription'; - - if (!hasValidQuery && !hasValidMutation && !hasValidSubscription) { - console.warn('No query, mutation or subscription was specified'); - } - - if (hasValidQuery) { - try { - data = null; - - const response = await API.graphql({ query, variables }); - - data = response.data; - } catch (err) { - data = err.data; - errors = err.errors; - } - } - - if (hasValidMutation) { - mutationProp = async (variables) => { - const result = await API.graphql({ query: mutation, variables }); - - this.forceUpdate(); - return result; - }; - } - - if (hasValidSubscription) { - const { query: subsQuery, variables: subsVars } = subscription; - - try { - const observable = API.graphql({ query: subsQuery, variables: subsVars }); - - this.subSubscription = observable.subscribe({ - next: ({ value: { data } }) => { - const { data: prevData } = this.state; - const newData = onSubscriptionMsg(prevData, data); - this.setState({ data: newData }); - }, - error: err => console.error(err), - }); - } catch (err) { - errors = err.errors; - } - } - - this.setState({ data, errors, mutation: mutationProp, loading: false }); - } - - _unsubscribe() { - if (this.subSubscription) { - this.subSubscription.unsubscribe(); - }; - } - - async componentDidMount() { - this._fetchData(); - } - - componentWillUnmount() { - this._unsubscribe(); - } - - componentDidUpdate(prevProps) { - const { loading } = this.state; - - const { query: newQueryObj, mutation: newMutationObj } = this.props; - const { query: prevQueryObj, mutation: prevMutationObj } = prevProps; - - // query - const { query: newQuery, variables: newQueryVariables } = newQueryObj || {}; - const { query: prevQuery, variables: prevQueryVariables } = prevQueryObj || {}; - const queryChanged = prevQuery !== newQuery || JSON.stringify(prevQueryVariables) !== JSON.stringify(newQueryVariables); - - // mutation - const { query: newMutation, variables: newMutationVariables } = newMutationObj || {}; - const { query: prevMutation, variables: prevMutationVariables } = prevMutationObj || {}; - const mutationChanged = prevMutation !== newMutation || JSON.stringify(prevMutationVariables) !== JSON.stringify(newMutationVariables); - - if (!loading && (queryChanged || mutationChanged)) { - this._fetchData(); - } - } - - render() { - const { data, loading, mutation, errors } = this.state; - - return this.props.children({ data, errors, loading, mutation }) || null; - } + constructor(props) { + super(props); + + this.state = this.getInitialState(); + this.subSubscription = null; + } + + getInitialState() { + const { query } = this.props; + return { + loading: query && !!query.query, + data: {}, + errors: [], + mutation: () => console.warn('Not implemented'), + }; + } + + getDefaultState() { + return { + loading: false, + data: {}, + errors: [], + mutation: () => console.warn('Not implemented'), + }; + } + + async _fetchData() { + this._unsubscribe(); + this.setState({ loading: true }); + + const { + query: { query, variables = {} } = {}, + mutation: { query: mutation, mutationVariables = {} } = {}, + subscription, + onSubscriptionMsg = prevData => prevData, + } = this.props; + + let { data, mutation: mutationProp, errors } = this.getDefaultState(); + + const hasValidQuery = query && getOperationType(query) === 'query'; + const hasValidMutation = + mutation && getOperationType(mutation) === 'mutation'; + const hasValidSubscription = + subscription && getOperationType(subscription.query) === 'subscription'; + + if (!hasValidQuery && !hasValidMutation && !hasValidSubscription) { + console.warn('No query, mutation or subscription was specified'); + } + + if (hasValidQuery) { + try { + data = null; + + const response = await API.graphql({ query, variables }); + + data = response.data; + } catch (err) { + data = err.data; + errors = err.errors; + } + } + + if (hasValidMutation) { + mutationProp = async variables => { + const result = await API.graphql({ query: mutation, variables }); + + this.forceUpdate(); + return result; + }; + } + + if (hasValidSubscription) { + const { query: subsQuery, variables: subsVars } = subscription; + + try { + const observable = API.graphql({ + query: subsQuery, + variables: subsVars, + }); + + this.subSubscription = observable.subscribe({ + next: ({ value: { data } }) => { + const { data: prevData } = this.state; + const newData = onSubscriptionMsg(prevData, data); + this.setState({ data: newData }); + }, + error: err => console.error(err), + }); + } catch (err) { + errors = err.errors; + } + } + + this.setState({ data, errors, mutation: mutationProp, loading: false }); + } + + _unsubscribe() { + if (this.subSubscription) { + this.subSubscription.unsubscribe(); + } + } + + async componentDidMount() { + this._fetchData(); + } + + componentWillUnmount() { + this._unsubscribe(); + } + + componentDidUpdate(prevProps) { + const { loading } = this.state; + + const { query: newQueryObj, mutation: newMutationObj } = this.props; + const { query: prevQueryObj, mutation: prevMutationObj } = prevProps; + + // query + const { query: newQuery, variables: newQueryVariables } = newQueryObj || {}; + const { query: prevQuery, variables: prevQueryVariables } = + prevQueryObj || {}; + const queryChanged = + prevQuery !== newQuery || + JSON.stringify(prevQueryVariables) !== JSON.stringify(newQueryVariables); + + // mutation + const { query: newMutation, variables: newMutationVariables } = + newMutationObj || {}; + const { query: prevMutation, variables: prevMutationVariables } = + prevMutationObj || {}; + const mutationChanged = + prevMutation !== newMutation || + JSON.stringify(prevMutationVariables) !== + JSON.stringify(newMutationVariables); + + if (!loading && (queryChanged || mutationChanged)) { + this._fetchData(); + } + } + + render() { + const { data, loading, mutation, errors } = this.state; + + return this.props.children({ data, errors, loading, mutation }) || null; + } } diff --git a/packages/aws-amplify-react-native/src/AmplifyI18n.js b/packages/aws-amplify-react-native/src/AmplifyI18n.js index 25623481cb6..00848f4e7d2 100644 --- a/packages/aws-amplify-react-native/src/AmplifyI18n.js +++ b/packages/aws-amplify-react-native/src/AmplifyI18n.js @@ -12,223 +12,229 @@ */ const dict = { - 'de': { - 'Loading...': "Lädt...", - 'Sign In': "Anmelden", - 'Sign Up': "Registrieren", - 'Sign Out': "Abmelden", - 'Sign in to your account': 'Melden Sie sich mit Ihrem Account an', - 'Username': "Benutzername", - 'Password': "Passwort", - 'Enter your username': "Geben Sie Ihren Benutzernamen ein", - 'Enter your password': "Geben Sie Ihr Passwort ein", - 'No account? ': "Kein Account? ", - 'Forget your password? ': 'Passwort vergessen? ', - 'Reset password': "Passwort zurücksetzen", - 'User does not exist': 'Dieser Benutzer existiert nicht', - 'User already exists': "Dieser Benutzer existiert bereits", - 'Incorrect username or password': "Falscher Benutzername oder falsches Passwort", - 'Invalid password format': "Ungültiges Passwort-Format", - 'Create account': "Hier registrieren", - 'Forgot Password': "Passwort vergessen", - 'Change Password': "Passwort ändern", - 'New Password': "Neues Passwort", - 'Email': "Email", - 'Phone Number': "Telefonnummer", - 'Confirm a Code': "Code bestätigen", - 'Confirm Sign In': "Anmeldung bestätigen", - 'Confirm Sign Up': "Registrierung bestätigen", - 'Back to Sign In': "Zurück zur Anmeldung", - 'Send Code': "Code senden", - 'Confirm': "Bestätigen", - 'Resend Code': "Code erneut senden", - 'Submit': "Abschicken", - 'Skip': "Überspringen", - 'Verify': "Verifizieren", - 'Verify Contact': "Kontakt verifizieren", - 'Code': "Code", - 'Confirmation Code': "Bestätigungs-Code", - 'Lost your code? ' : "Code verloren? ", - 'Account recovery requires verified contact information': - "Zurücksetzen des Account benötigt einen verifizierten Account", - 'Invalid phone number format': - `Ungültiges Telefonummern-Format. + de: { + 'Loading...': 'Lädt...', + 'Sign In': 'Anmelden', + 'Sign Up': 'Registrieren', + 'Sign Out': 'Abmelden', + 'Sign in to your account': 'Melden Sie sich mit Ihrem Account an', + Username: 'Benutzername', + Password: 'Passwort', + 'Enter your username': 'Geben Sie Ihren Benutzernamen ein', + 'Enter your password': 'Geben Sie Ihr Passwort ein', + 'No account? ': 'Kein Account? ', + 'Forget your password? ': 'Passwort vergessen? ', + 'Reset password': 'Passwort zurücksetzen', + 'User does not exist': 'Dieser Benutzer existiert nicht', + 'User already exists': 'Dieser Benutzer existiert bereits', + 'Incorrect username or password': + 'Falscher Benutzername oder falsches Passwort', + 'Invalid password format': 'Ungültiges Passwort-Format', + 'Create account': 'Hier registrieren', + 'Forgot Password': 'Passwort vergessen', + 'Change Password': 'Passwort ändern', + 'New Password': 'Neues Passwort', + Email: 'Email', + 'Phone Number': 'Telefonnummer', + 'Confirm a Code': 'Code bestätigen', + 'Confirm Sign In': 'Anmeldung bestätigen', + 'Confirm Sign Up': 'Registrierung bestätigen', + 'Back to Sign In': 'Zurück zur Anmeldung', + 'Send Code': 'Code senden', + Confirm: 'Bestätigen', + 'Resend Code': 'Code erneut senden', + Submit: 'Abschicken', + Skip: 'Überspringen', + Verify: 'Verifizieren', + 'Verify Contact': 'Kontakt verifizieren', + Code: 'Code', + 'Confirmation Code': 'Bestätigungs-Code', + 'Lost your code? ': 'Code verloren? ', + 'Account recovery requires verified contact information': + 'Zurücksetzen des Account benötigt einen verifizierten Account', + 'Invalid phone number format': `Ungültiges Telefonummern-Format. Benutze eine Nummer im Format: +12345678900`, - 'Create Account': "Account erstellen", - 'Have an account? ': "Schon registriert? ", - 'Sign in': "Anmelden", - 'Create a new account': "Erstelle einen neuen Account", - 'Reset your password': "Zurücksetzen des Passworts", - 'An account with the given email already exists.': "Ein Account mit dieser Email existiert bereits.", - 'Username cannot be empty': "Benutzername darf nicht leer sein", - 'Password attempts exceeded': "Die maximale Anzahl der fehlerhaften Anmeldeversuche wurde erreicht" - }, - 'fr': { - 'Loading...': "S'il vous plaît, attendez", - 'Sign In': "Se connecter", - 'Sign Up': "S'inscrire", - 'Sign Out': "Déconnexion", - 'Forgot Password': "Mot de passe oublié", - 'Username': "Nom d'utilisateur", - 'Password': "Mot de passe", - 'Change Password': "Changer le mot de passe", - 'New Password': "nouveau mot de passe", - 'Email': "Email", - 'Phone Number': "Numéro de téléphone", - 'Confirm a Code': "Confirmer un code", - 'Confirm Sign In': "Confirmer la connexion", - 'Confirm Sign Up': "Confirmer l'inscription", - 'Back to Sign In': "Retour à la connexion", - 'Send Code': "Envoyer le code", - 'Confirm': "Confirmer", - 'Resend a Code': "Renvoyer un code", - 'Submit': "Soumettre", - 'Skip': "Sauter", - 'Verify': "Vérifier", - 'Verify Contact': "Vérifier le contact", - 'Code': "Code", - 'Account recovery requires verified contact information': - "La récupération du compte nécessite des informations de contact vérifiées", + 'Create Account': 'Account erstellen', + 'Have an account? ': 'Schon registriert? ', + 'Sign in': 'Anmelden', + 'Create a new account': 'Erstelle einen neuen Account', + 'Reset your password': 'Zurücksetzen des Passworts', + 'An account with the given email already exists.': + 'Ein Account mit dieser Email existiert bereits.', + 'Username cannot be empty': 'Benutzername darf nicht leer sein', + 'Password attempts exceeded': + 'Die maximale Anzahl der fehlerhaften Anmeldeversuche wurde erreicht', + }, + fr: { + 'Loading...': "S'il vous plaît, attendez", + 'Sign In': 'Se connecter', + 'Sign Up': "S'inscrire", + 'Sign Out': 'Déconnexion', + 'Forgot Password': 'Mot de passe oublié', + Username: "Nom d'utilisateur", + Password: 'Mot de passe', + 'Change Password': 'Changer le mot de passe', + 'New Password': 'nouveau mot de passe', + Email: 'Email', + 'Phone Number': 'Numéro de téléphone', + 'Confirm a Code': 'Confirmer un code', + 'Confirm Sign In': 'Confirmer la connexion', + 'Confirm Sign Up': "Confirmer l'inscription", + 'Back to Sign In': 'Retour à la connexion', + 'Send Code': 'Envoyer le code', + Confirm: 'Confirmer', + 'Resend a Code': 'Renvoyer un code', + Submit: 'Soumettre', + Skip: 'Sauter', + Verify: 'Vérifier', + 'Verify Contact': 'Vérifier le contact', + Code: 'Code', + 'Account recovery requires verified contact information': + 'La récupération du compte nécessite des informations de contact vérifiées', - 'User does not exist': "L'utilisateur n'existe pas", - 'User already exists': "L'utilisateur existe déjà", - 'Incorrect username or password': "identifiant ou mot de passe incorrect", - 'Invalid password format': "format de mot de passe invalide", - 'Invalid phone number format': - `Format de numéro de téléphone invalide. + 'User does not exist': "L'utilisateur n'existe pas", + 'User already exists': "L'utilisateur existe déjà", + 'Incorrect username or password': 'identifiant ou mot de passe incorrect', + 'Invalid password format': 'format de mot de passe invalide', + 'Invalid phone number format': `Format de numéro de téléphone invalide. Veuillez utiliser un format de numéro de téléphone du +12345678900`, - 'Sign in to your account': "Connectez-vous à votre compte", - 'Forget your password? ': "Mot de passe oublié ? ", - 'Reset password': "Réinitialisez votre mot de passe", - 'No account? ': "Pas de compte ? ", - 'Create account': "Créer un compte", - 'Create Account': "Créer un compte", - 'Have an account? ': "Déjà un compte ? ", - 'Sign in': "Se connecter", - 'Create a new account': "Créer un nouveau compte", - 'Reset your password': "Réinitialisez votre mot de passe", - 'Enter your username': "Saisissez votre nom d'utilisateur", - 'Enter your password': "Saisissez votre mot de passe", - 'An account with the given email already exists.': "Un utilisateur avec cette adresse email existe déjà.", - 'Username cannot be empty': "Le nom d'utilisateur doit être renseigné" - }, + 'Sign in to your account': 'Connectez-vous à votre compte', + 'Forget your password? ': 'Mot de passe oublié ? ', + 'Reset password': 'Réinitialisez votre mot de passe', + 'No account? ': 'Pas de compte ? ', + 'Create account': 'Créer un compte', + 'Create Account': 'Créer un compte', + 'Have an account? ': 'Déjà un compte ? ', + 'Sign in': 'Se connecter', + 'Create a new account': 'Créer un nouveau compte', + 'Reset your password': 'Réinitialisez votre mot de passe', + 'Enter your username': "Saisissez votre nom d'utilisateur", + 'Enter your password': 'Saisissez votre mot de passe', + 'An account with the given email already exists.': + 'Un utilisateur avec cette adresse email existe déjà.', + 'Username cannot be empty': "Le nom d'utilisateur doit être renseigné", + }, - 'es': { - 'Loading...': "Espere por favor", - 'Sign In': "Registrarse", - 'Sign Up': "Regístrate", - 'Sign Out': "Desconectar", - 'Forgot Password': "Se te olvidó tu contraseña", - 'Username': "Nombre de usuario", - 'Password': "Contraseña", - 'Change Password': "Cambia la contraseña", - 'New Password': "Nueva contraseña", - 'Email': "Email", - 'Phone Number': "Número de teléfono", - 'Confirm a Code': "Confirmar un código", - 'Confirm Sign In': "Confirmar inicio de sesión", - 'Confirm Sign Up': "Confirmar Registrarse", - 'Back to Sign In': "Volver a Iniciar sesión", - 'Send Code': "Enviar código", - 'Confirm': "Confirmar", - 'Resend a Code': "Reenviar un código", - 'Submit': "Enviar", - 'Skip': "Omitir", - 'Verify': "Verificar", - 'Verify Contact': "Verificar contacto", - 'Code': "Código", - 'Account recovery requires verified contact information': - "La recuperación de la cuenta requiere información de contacto verificada", + es: { + 'Loading...': 'Espere por favor', + 'Sign In': 'Registrarse', + 'Sign Up': 'Regístrate', + 'Sign Out': 'Desconectar', + 'Forgot Password': 'Se te olvidó tu contraseña', + Username: 'Nombre de usuario', + Password: 'Contraseña', + 'Change Password': 'Cambia la contraseña', + 'New Password': 'Nueva contraseña', + Email: 'Email', + 'Phone Number': 'Número de teléfono', + 'Confirm a Code': 'Confirmar un código', + 'Confirm Sign In': 'Confirmar inicio de sesión', + 'Confirm Sign Up': 'Confirmar Registrarse', + 'Back to Sign In': 'Volver a Iniciar sesión', + 'Send Code': 'Enviar código', + Confirm: 'Confirmar', + 'Resend a Code': 'Reenviar un código', + Submit: 'Enviar', + Skip: 'Omitir', + Verify: 'Verificar', + 'Verify Contact': 'Verificar contacto', + Code: 'Código', + 'Account recovery requires verified contact information': + 'La recuperación de la cuenta requiere información de contacto verificada', - 'User does not exist': "el usuario no existe", - 'User already exists': "El usuario ya existe", - 'Incorrect username or password': "Nombre de usuario o contraseña incorrecta", - 'Invalid password format': "Formato de contraseña inválido", - 'Invalid phone number format': - `Formato de número de teléfono inválido. -Utilice el formato de número de teléfono +12345678900` - }, - 'it': { - "Loading": "Caricamento in corso", - "Account recovery requires verified contact information": "Ripristino del conto richiede un account verificati", - "An account with the given email already exists.": "Un account con questa email esiste già.", - "Back to Sign In": "Torna alla Login", - "Change Password": "Cambia la password", - "Code": "Codice", - "Confirm": "Conferma", - "Confirm Sign In": "Conferma di applicazione", - "Confirm Sign Up": "Registrazione Conferma", - "Confirm a Code": "Codice Conferma", - "Confirmation Code": "Codice di verifica", - "Create Account": "Crea account", - "Create a new account": "Creare un nuovo account", - "Create account": "Registrati", - "Email": "E-mail", - "Enter your password": "Inserire la password", - "Enter your username": "Inserisci il tuo nome utente", - "Forget your password?" : "Password dimenticata?", - "Forgot Password": "Password dimenticata", - "Have an account? ": "Già registrato?", - "Incorrect username or password": "Nome utente o password errati", - "Invalid password format": "Formato della password non valido", - "Invalid phone number format": "Utilizzo non valido Telefonummern formattare un numero nel formato :. 12.345.678,9 mille", - "Lost your code?" : "Perso codice?", - "New Password": "Nuova password", - "No account? ": "Nessun account?", - "Password": "Password", - "Password attempts exceeded": "Il numero massimo di tentativi di accesso falliti è stato raggiunto", - "Phone Number": "Numero di telefono", - "Resend Code": "Codice Rispedisci", - "Reset password": "Ripristina password", - "Reset your password": "Resetta password", - "Send Code": "Invia codice", - "Sign In": "Accesso", - "Sign Out": "Esci", - "Sign Up": "Iscriviti", - "Sign in": "Accesso", - "Sign in to your account": "Accedi con il tuo account a", - "Skip": "Salta", - "Submit": "Sottoscrivi", - "User already exists": "Questo utente esiste già", - "User does not exist": "Questo utente non esiste", - "Username": "Nome utente", - "Username cannot be empty": "Nome utente non può essere vuoto", - "Verify": "Verifica", - "Verify Contact": "Contatto verifica" - }, - 'zh': { - 'Loading...': "请稍候", - 'Sign In': "登录", - 'Sign Up': "注册", - 'Sign Out': "退出", - 'Forgot Password': "忘记密码", - 'Username': "用户名", - 'Password': "密码", - 'Change Password': "改变密码", - 'New Password': "新密码", - 'Email': "邮箱", - 'Phone Number': "电话", - 'Confirm a Code': "确认码", - 'Confirm Sign In': "确认登录", - 'Confirm Sign Up': "确认注册", - 'Back to Sign In': "回到登录", - 'Send Code': "发送确认码", - 'Confirm': "确认", - 'Resend a Code': "重发确认码", - 'Submit': "提交", - 'Skip': "跳过", - 'Verify': "验证", - 'Verify Contact': "验证联系方式", - 'Code': "确认码", - 'Account recovery requires verified contact information': - "账户恢复需要验证过的联系方式", + 'User does not exist': 'el usuario no existe', + 'User already exists': 'El usuario ya existe', + 'Incorrect username or password': + 'Nombre de usuario o contraseña incorrecta', + 'Invalid password format': 'Formato de contraseña inválido', + 'Invalid phone number format': `Formato de número de teléfono inválido. +Utilice el formato de número de teléfono +12345678900`, + }, + it: { + Loading: 'Caricamento in corso', + 'Account recovery requires verified contact information': + 'Ripristino del conto richiede un account verificati', + 'An account with the given email already exists.': + 'Un account con questa email esiste già.', + 'Back to Sign In': 'Torna alla Login', + 'Change Password': 'Cambia la password', + Code: 'Codice', + Confirm: 'Conferma', + 'Confirm Sign In': 'Conferma di applicazione', + 'Confirm Sign Up': 'Registrazione Conferma', + 'Confirm a Code': 'Codice Conferma', + 'Confirmation Code': 'Codice di verifica', + 'Create Account': 'Crea account', + 'Create a new account': 'Creare un nuovo account', + 'Create account': 'Registrati', + Email: 'E-mail', + 'Enter your password': 'Inserire la password', + 'Enter your username': 'Inserisci il tuo nome utente', + 'Forget your password?': 'Password dimenticata?', + 'Forgot Password': 'Password dimenticata', + 'Have an account? ': 'Già registrato?', + 'Incorrect username or password': 'Nome utente o password errati', + 'Invalid password format': 'Formato della password non valido', + 'Invalid phone number format': + 'Utilizzo non valido Telefonummern formattare un numero nel formato :. 12.345.678,9 mille', + 'Lost your code?': 'Perso codice?', + 'New Password': 'Nuova password', + 'No account? ': 'Nessun account?', + Password: 'Password', + 'Password attempts exceeded': + 'Il numero massimo di tentativi di accesso falliti è stato raggiunto', + 'Phone Number': 'Numero di telefono', + 'Resend Code': 'Codice Rispedisci', + 'Reset password': 'Ripristina password', + 'Reset your password': 'Resetta password', + 'Send Code': 'Invia codice', + 'Sign In': 'Accesso', + 'Sign Out': 'Esci', + 'Sign Up': 'Iscriviti', + 'Sign in': 'Accesso', + 'Sign in to your account': 'Accedi con il tuo account a', + Skip: 'Salta', + Submit: 'Sottoscrivi', + 'User already exists': 'Questo utente esiste già', + 'User does not exist': 'Questo utente non esiste', + Username: 'Nome utente', + 'Username cannot be empty': 'Nome utente non può essere vuoto', + Verify: 'Verifica', + 'Verify Contact': 'Contatto verifica', + }, + zh: { + 'Loading...': '请稍候', + 'Sign In': '登录', + 'Sign Up': '注册', + 'Sign Out': '退出', + 'Forgot Password': '忘记密码', + Username: '用户名', + Password: '密码', + 'Change Password': '改变密码', + 'New Password': '新密码', + Email: '邮箱', + 'Phone Number': '电话', + 'Confirm a Code': '确认码', + 'Confirm Sign In': '确认登录', + 'Confirm Sign Up': '确认注册', + 'Back to Sign In': '回到登录', + 'Send Code': '发送确认码', + Confirm: '确认', + 'Resend a Code': '重发确认码', + Submit: '提交', + Skip: '跳过', + Verify: '验证', + 'Verify Contact': '验证联系方式', + Code: '确认码', + 'Account recovery requires verified contact information': + '账户恢复需要验证过的联系方式', - 'User does not exist': "用户不存在", - 'User already exists': "用户已经存在", - 'Incorrect username or password': "用户名或密码错误", - 'Invalid password format': "密码格式错误", - 'Invalid phone number format': "电话格式错误,请使用格式 +12345678900" - } + 'User does not exist': '用户不存在', + 'User already exists': '用户已经存在', + 'Incorrect username or password': '用户名或密码错误', + 'Invalid password format': '密码格式错误', + 'Invalid phone number format': '电话格式错误,请使用格式 +12345678900', + }, }; export default dict; diff --git a/packages/aws-amplify-react-native/src/AmplifyMessageMap.js b/packages/aws-amplify-react-native/src/AmplifyMessageMap.js index a98206c5292..c368d26fa2c 100644 --- a/packages/aws-amplify-react-native/src/AmplifyMessageMap.js +++ b/packages/aws-amplify-react-native/src/AmplifyMessageMap.js @@ -14,25 +14,25 @@ import { I18n } from 'aws-amplify'; export const MapEntries = [ - ['User does not exist', /user.*not.*exist/i], - ['User already exists', /user.*already.*exist/i], - ['Incorrect username or password', /incorrect.*username.*password/i], - ['Invalid password format', /validation.*password/i], - [ - 'Invalid phone number format', - /invalid.*phone/i, - 'Invalid phone number format. Please use a phone number format of +12345678900' - ] + ['User does not exist', /user.*not.*exist/i], + ['User already exists', /user.*already.*exist/i], + ['Incorrect username or password', /incorrect.*username.*password/i], + ['Invalid password format', /validation.*password/i], + [ + 'Invalid phone number format', + /invalid.*phone/i, + 'Invalid phone number format. Please use a phone number format of +12345678900', + ], ]; -export default (message) => { - const match = MapEntries.filter(entry => entry[1].test(message)); - if (match.length === 0) { - return message; - } +export default message => { + const match = MapEntries.filter(entry => entry[1].test(message)); + if (match.length === 0) { + return message; + } - const entry = match[0]; - const msg = entry.length > 2? entry[2] : entry[0]; + const entry = match[0]; + const msg = entry.length > 2 ? entry[2] : entry[0]; - return I18n.get(entry[0], msg); -} + return I18n.get(entry[0], msg); +}; diff --git a/packages/aws-amplify-react-native/src/AmplifyTheme.js b/packages/aws-amplify-react-native/src/AmplifyTheme.js index 374224b9041..8285f500927 100644 --- a/packages/aws-amplify-react-native/src/AmplifyTheme.js +++ b/packages/aws-amplify-react-native/src/AmplifyTheme.js @@ -20,116 +20,115 @@ export const errorIconColor = '#DD3F5B'; // Theme export default StyleSheet.create({ - container: { - flex: 1, - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'space-around', - paddingTop: 20, - width: '100%', - backgroundColor: '#FFF', - }, - section: { - flex: 1, - width: '100%', - padding: 20, - }, - sectionHeader: { - width: '100%', - marginBottom: 32 - }, - sectionHeaderText: { - color: deepSquidInk, - fontSize: 20, - fontWeight: '500' - }, - sectionFooter: { - width: '100%', - padding: 10, - flexDirection: 'row', - justifyContent: 'space-between', - marginTop: 15, - marginBottom: 20 - }, - sectionFooterLink: { - fontSize: 14, - color: '#ff9900', - alignItems: 'baseline', - textAlign: 'center' - }, - navBar: { - marginTop: 35, - padding: 15, - flexDirection:'row', - justifyContent: 'flex-end', - alignItems: 'center' - }, - navButton: { - marginLeft: 12, - borderRadius: 4 - }, - cell: { - flex: 1, - width: '50%' - }, - errorRow: { - flexDirection: 'row', - justifyContent: 'center' - }, - errorRowText: { - marginLeft: 10 - }, - photo: { - width: '100%' - }, - album: { - width: '100%' - }, - button: { - backgroundColor: '#ff9900', - alignItems: 'center', - padding: 16, - }, - buttonDisabled: { - backgroundColor: '#ff990080', - alignItems: 'center', - padding: 16, - }, - buttonText: { - color: '#fff', - fontSize: 14, - fontWeight: '600' - }, - formField: { - marginBottom: 22 - }, - input: { - padding: 16, - borderWidth: 1, - borderRadius: 3, - borderColor: "#C4C4C4", - }, - inputLabel: { - marginBottom: 8 - }, - phoneContainer: { - display: 'flex', - flexDirection: 'row', - alignItems: 'center', - }, - phoneInput: { - flex: 2, - padding: 16, - borderWidth: 1, - borderRadius: 3, - borderColor: "#C4C4C4", - }, - picker: { - flex: 1, - height: 44, - }, - pickerItem: { - height: 44, - }, + container: { + flex: 1, + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'space-around', + paddingTop: 20, + width: '100%', + backgroundColor: '#FFF', + }, + section: { + flex: 1, + width: '100%', + padding: 20, + }, + sectionHeader: { + width: '100%', + marginBottom: 32, + }, + sectionHeaderText: { + color: deepSquidInk, + fontSize: 20, + fontWeight: '500', + }, + sectionFooter: { + width: '100%', + padding: 10, + flexDirection: 'row', + justifyContent: 'space-between', + marginTop: 15, + marginBottom: 20, + }, + sectionFooterLink: { + fontSize: 14, + color: '#ff9900', + alignItems: 'baseline', + textAlign: 'center', + }, + navBar: { + marginTop: 35, + padding: 15, + flexDirection: 'row', + justifyContent: 'flex-end', + alignItems: 'center', + }, + navButton: { + marginLeft: 12, + borderRadius: 4, + }, + cell: { + flex: 1, + width: '50%', + }, + errorRow: { + flexDirection: 'row', + justifyContent: 'center', + }, + errorRowText: { + marginLeft: 10, + }, + photo: { + width: '100%', + }, + album: { + width: '100%', + }, + button: { + backgroundColor: '#ff9900', + alignItems: 'center', + padding: 16, + }, + buttonDisabled: { + backgroundColor: '#ff990080', + alignItems: 'center', + padding: 16, + }, + buttonText: { + color: '#fff', + fontSize: 14, + fontWeight: '600', + }, + formField: { + marginBottom: 22, + }, + input: { + padding: 16, + borderWidth: 1, + borderRadius: 3, + borderColor: '#C4C4C4', + }, + inputLabel: { + marginBottom: 8, + }, + phoneContainer: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + }, + phoneInput: { + flex: 2, + padding: 16, + borderWidth: 1, + borderRadius: 3, + borderColor: '#C4C4C4', + }, + picker: { + flex: 1, + height: 44, + }, + pickerItem: { + height: 44, + }, }); - diff --git a/packages/aws-amplify-react-native/src/AmplifyUI.js b/packages/aws-amplify-react-native/src/AmplifyUI.js index 12c31dddcce..516300a68d2 100644 --- a/packages/aws-amplify-react-native/src/AmplifyUI.js +++ b/packages/aws-amplify-react-native/src/AmplifyUI.js @@ -12,141 +12,159 @@ */ import React, { Component } from 'react'; -import { View, Text, TextInput, TouchableHighlight, TouchableOpacity, Picker } from 'react-native'; +import { + View, + Text, + TextInput, + TouchableHighlight, + TouchableOpacity, + Picker, +} from 'react-native'; import { I18n } from 'aws-amplify'; -import AmplifyTheme, { linkUnderlayColor, errorIconColor } from './AmplifyTheme'; +import AmplifyTheme, { + linkUnderlayColor, + errorIconColor, +} from './AmplifyTheme'; import { Icon } from 'react-native-elements'; import countryDialCodes from './CountryDialCodes'; -export const FormField = (props) => { - const theme = props.theme || AmplifyTheme; - return ( - - {props.label} {props.required ? '*' : ''} - - - ) -} +export const FormField = props => { + const theme = props.theme || AmplifyTheme; + return ( + + + {props.label} {props.required ? '*' : ''} + + + + ); +}; export class PhoneField extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.state = { - dialCode: this.props.defaultDialCode || '+1', - phone: '', - }; - } + this.state = { + dialCode: this.props.defaultDialCode || '+1', + phone: '', + }; + } - onChangeText() { - const { dialCode, phone } = this.state; - const cleanedPhone = phone.replace(/[^0-9.]/g, '') || ''; - const phoneNumber = cleanedPhone === '' ? '' : `${dialCode}${cleanedPhone}`; - this.props.onChangeText(phoneNumber); - } + onChangeText() { + const { dialCode, phone } = this.state; + const cleanedPhone = phone.replace(/[^0-9.]/g, '') || ''; + const phoneNumber = cleanedPhone === '' ? '' : `${dialCode}${cleanedPhone}`; + this.props.onChangeText(phoneNumber); + } - render() { - const { label, required } = this.props; - const theme = this.props.theme || AmplifyTheme; + render() { + const { label, required } = this.props; + const theme = this.props.theme || AmplifyTheme; - return ( - - {label} {required ? '*' : ''} - - { - this.setState({ dialCode }, () => { - this.onChangeText(); - }); - }}> - {countryDialCodes.map(dialCode => - - )} - - { - this.setState({ phone }, () => { - this.onChangeText(); - }); - }} - /> - - - ) - } + return ( + + + {label} {required ? '*' : ''} + + + { + this.setState({ dialCode }, () => { + this.onChangeText(); + }); + }} + > + {countryDialCodes.map(dialCode => ( + + ))} + + { + this.setState({ phone }, () => { + this.onChangeText(); + }); + }} + /> + + + ); + } } -export const SectionFooter = (props) => { - const theme = props.theme || AmplifyTheme; - return ( - - onStateChange('confirmSignUp')}> - {I18n.get('Confirm a Code')} - - onStateChange('signIn')}> - {I18n.get('Sign In')} - - - ) -} +export const SectionFooter = props => { + const theme = props.theme || AmplifyTheme; + return ( + + onStateChange('confirmSignUp')}> + {I18n.get('Confirm a Code')} + + onStateChange('signIn')}> + {I18n.get('Sign In')} + + + ); +}; -export const LinkCell = (props) => { - const theme = props.theme || AmplifyTheme; - return ( - - - {props.children} - - - ) -} +export const LinkCell = props => { + const theme = props.theme || AmplifyTheme; + return ( + + + {props.children} + + + ); +}; -export const Header = (props) => { - const theme = props.theme || AmplifyTheme; - return ( - - {props.children} - - ) -} +export const Header = props => { + const theme = props.theme || AmplifyTheme; + return ( + + {props.children} + + ); +}; -export const ErrorRow = (props) => { - const theme = props.theme || AmplifyTheme; - if (!props.children) return null; - return ( - - - {props.children} - - ) -} +export const ErrorRow = props => { + const theme = props.theme || AmplifyTheme; + if (!props.children) return null; + return ( + + + {props.children} + + ); +}; -export const AmplifyButton = (props) => { - const theme = props.theme || AmplifyTheme; - let style = theme.button; - if (props.disabled) { - style = theme.buttonDisabled; - } +export const AmplifyButton = props => { + const theme = props.theme || AmplifyTheme; + let style = theme.button; + if (props.disabled) { + style = theme.buttonDisabled; + } - if (props.style) { - style = [style, props.style]; - } + if (props.style) { + style = [style, props.style]; + } - return ( - - {props.text} - - ) -} + return ( + + {props.text} + + ); +}; diff --git a/packages/aws-amplify-react-native/src/Auth/AuthPiece.js b/packages/aws-amplify-react-native/src/Auth/AuthPiece.js index 1bc9ebd22f2..52e0754cd71 100644 --- a/packages/aws-amplify-react-native/src/Auth/AuthPiece.js +++ b/packages/aws-amplify-react-native/src/Auth/AuthPiece.js @@ -13,147 +13,139 @@ import React from 'react'; -import { - Auth, - Logger, - JS, - I18n -} from 'aws-amplify'; +import { Auth, Logger, JS, I18n } from 'aws-amplify'; import AmplifyTheme from '../AmplifyTheme'; import AmplifyMessageMap from '../AmplifyMessageMap'; -import { - FormField, - PhoneField -} from '../AmplifyUI'; +import { FormField, PhoneField } from '../AmplifyUI'; const logger = new Logger('AuthPiece'); const labelMap = { - email: 'Email', - phone_number: 'Phone Number', - username: 'Username' + email: 'Email', + phone_number: 'Phone Number', + username: 'Username', }; export default class AuthPiece extends React.Component { - constructor(props) { - super(props); - - this._isHidden = true; - this._validAuthStates = []; - this.changeState = this.changeState.bind(this); - this.error = this.error.bind(this); - - this.getUsernameFromInput = this.getUsernameFromInput.bind(this); - this.renderUsernameField = this.renderUsernameField.bind(this); - } - - getUsernameFromInput() { - const { usernameAttributes = 'username' } = this.props; - switch(usernameAttributes) { - case 'email': - return this.state.email; - case 'phone_number': - return this.state.phone_number; - default: - return this.state.username; - } - } - - renderUsernameField(theme) { - const { usernameAttributes = [] } = this.props; - if (usernameAttributes === 'email') { - return ( - this.setState({ email: text })} - label={I18n.get('Email')} - placeholder={I18n.get('Enter your email')} - required={true} - /> - ); - } else if (usernameAttributes === 'phone_number') { - return ( - this.setState({ phone_number: text })} - label={I18n.get('Phone Number')} - placeholder={I18n.get('Enter your phone number')} - keyboardType="phone-pad" - required={true} - /> - ); - } else { - return ( - this.setState({ username: text })} - label={I18n.get(this.getUsernameLabel())} - placeholder={I18n.get('Enter your username')} - required={true} - /> - ); - } - } - - getUsernameLabel() { - const { usernameAttributes = 'username' } = this.props; - return labelMap[usernameAttributes] || usernameAttributes; - } - - changeState(state, data) { - if (this.props.onStateChange) { - this.props.onStateChange(state, data); - } - } - - checkContact(user) { - Auth.verifiedContact(user) - .then(data => { - logger.debug('verified user attributes', data); - if (!JS.isEmpty(data.verified)) { - this.changeState('signedIn', user); - } else { - user = Object.assign(user, data); - this.changeState('verifyContact', user); - } - }); - } - - error(err) { - logger.debug(err); - - let msg = ''; - if (typeof err === 'string') { - msg = err; - } else if (err.message) { - msg = err.message; - } else { - msg = JSON.stringify(err); - } - - const map = this.props.errorMessage || this.props.messageMap || AmplifyMessageMap; - msg = (typeof map === 'string')? map : map(msg); - this.setState({ error: msg }); - } - - render() { - if (!this._validAuthStates.includes(this.props.authState)) { - this._isHidden = true; - return null; - } - - if (this._isHidden) { - const { track } = this.props; - if (track) track(); - } - this._isHidden = false; - - return this.showComponent(this.props.theme || AmplifyTheme); - } - - showComponent(theme) { - throw 'You must implement showComponent(theme) and don\'t forget to set this._validAuthStates.'; - } + constructor(props) { + super(props); + + this._isHidden = true; + this._validAuthStates = []; + this.changeState = this.changeState.bind(this); + this.error = this.error.bind(this); + + this.getUsernameFromInput = this.getUsernameFromInput.bind(this); + this.renderUsernameField = this.renderUsernameField.bind(this); + } + + getUsernameFromInput() { + const { usernameAttributes = 'username' } = this.props; + switch (usernameAttributes) { + case 'email': + return this.state.email; + case 'phone_number': + return this.state.phone_number; + default: + return this.state.username; + } + } + + renderUsernameField(theme) { + const { usernameAttributes = [] } = this.props; + if (usernameAttributes === 'email') { + return ( + this.setState({ email: text })} + label={I18n.get('Email')} + placeholder={I18n.get('Enter your email')} + required={true} + /> + ); + } else if (usernameAttributes === 'phone_number') { + return ( + this.setState({ phone_number: text })} + label={I18n.get('Phone Number')} + placeholder={I18n.get('Enter your phone number')} + keyboardType="phone-pad" + required={true} + /> + ); + } else { + return ( + this.setState({ username: text })} + label={I18n.get(this.getUsernameLabel())} + placeholder={I18n.get('Enter your username')} + required={true} + /> + ); + } + } + + getUsernameLabel() { + const { usernameAttributes = 'username' } = this.props; + return labelMap[usernameAttributes] || usernameAttributes; + } + + changeState(state, data) { + if (this.props.onStateChange) { + this.props.onStateChange(state, data); + } + } + + checkContact(user) { + Auth.verifiedContact(user).then(data => { + logger.debug('verified user attributes', data); + if (!JS.isEmpty(data.verified)) { + this.changeState('signedIn', user); + } else { + user = Object.assign(user, data); + this.changeState('verifyContact', user); + } + }); + } + + error(err) { + logger.debug(err); + + let msg = ''; + if (typeof err === 'string') { + msg = err; + } else if (err.message) { + msg = err.message; + } else { + msg = JSON.stringify(err); + } + + const map = + this.props.errorMessage || this.props.messageMap || AmplifyMessageMap; + msg = typeof map === 'string' ? map : map(msg); + this.setState({ error: msg }); + } + + render() { + if (!this._validAuthStates.includes(this.props.authState)) { + this._isHidden = true; + return null; + } + + if (this._isHidden) { + const { track } = this.props; + if (track) track(); + } + this._isHidden = false; + + return this.showComponent(this.props.theme || AmplifyTheme); + } + + showComponent(theme) { + throw "You must implement showComponent(theme) and don't forget to set this._validAuthStates."; + } } diff --git a/packages/aws-amplify-react-native/src/Auth/Authenticator.js b/packages/aws-amplify-react-native/src/Auth/Authenticator.js index c82d19538a8..b8dc66eb454 100644 --- a/packages/aws-amplify-react-native/src/Auth/Authenticator.js +++ b/packages/aws-amplify-react-native/src/Auth/Authenticator.js @@ -13,13 +13,7 @@ import React from 'react'; import { SafeAreaView } from 'react-native'; -import { - Auth, - Analytics, - Logger, - Hub, - JS -} from 'aws-amplify'; +import { Auth, Analytics, Logger, Hub, JS } from 'aws-amplify'; import AmplifyTheme from '../AmplifyTheme'; import AmplifyMessageMap from '../AmplifyMessageMap'; import Loading from './Loading'; @@ -35,158 +29,159 @@ import Greetings from './Greetings'; const logger = new Logger('Authenticator'); class AuthDecorator { - constructor(onStateChange) { - this.onStateChange = onStateChange; - } - - signIn(username, password) { - const that = this; - return Auth.signIn(username, password) - .then(data => { - that.onStateChange('signedIn'); - return data; - }); - } - - signOut() { - const that = this; - return Auth.signOut() - .then(() => { - that.onStateChange('signedOut'); - }); - } + constructor(onStateChange) { + this.onStateChange = onStateChange; + } + + signIn(username, password) { + const that = this; + return Auth.signIn(username, password).then(data => { + that.onStateChange('signedIn'); + return data; + }); + } + + signOut() { + const that = this; + return Auth.signOut().then(() => { + that.onStateChange('signedOut'); + }); + } } export default class Authenticator extends React.Component { - constructor(props) { - super(props); - this._initialAuthState = this.props.authState || 'signIn'; - this.state = { - authState: props.authState || 'loading', - authData: props.authData - }; - - this.handleStateChange = this.handleStateChange.bind(this); - this.checkUser = this.checkUser.bind(this); - this.onHubCapsule = this.onHubCapsule.bind(this); - this.checkContact = this.checkContact.bind(this); - - Hub.listen('auth', this.onHubCapsule); - } - - componentDidMount() { - this._isMounted = true; - this.checkUser(); - } - - componentWillUnmount() { - this._isMounted = false; - } - - onHubCapsule(capsule) { - const { channel, payload, source } = capsule; - if (channel === 'auth') { this.checkUser(); } - } - - handleStateChange(state, data) { - logger.debug('authenticator state change ' + state); - if (!this._isMounted) return; - if (state === this.state.authState) { return; } - - if (state === 'signedOut') { state = 'signIn'; } - this.setState({ authState: state, authData: data, error: null }); - if (this.props.onStateChange) { this.props.onStateChange(state, data); } - - switch(state) { - case 'signedIn': - Analytics.record('_userauth.sign_in'); - break; - case 'signedUp': - Analytics.record('_userauth.sign_up'); - break; - } - } - - async checkContact(user) { - try { - const data = await Auth.verifiedContact(user); - logger.debug('verified user attributes', data); - if (!JS.isEmpty(data.verified)) { - this.handleStateChange('signedIn', user); - } else { - user = Object.assign(user, data); - this.handleStateChange('verifyContact', user); - } - } catch (e) { - logger.warn('Failed to verify contact', e); - this.handleStateChange('signedIn', user); - } - } - - checkUser() { - const { authState } = this.state; - const statesJumpToSignIn = ['signedIn', 'signedOut', 'loading']; - Auth.currentAuthenticatedUser() - .then(user => { - if (!this._isMounted) return; - if (user) { - this.checkContact(user); - } else { - if (statesJumpToSignIn.includes(authState)) { - this.handleStateChange(this._initialAuthState, null); - } - } - }) - .catch(err => { - if (!this._isMounted) return; - logger.debug(err); - if (statesJumpToSignIn.includes(authState)) { - Auth.signOut() - .then(() => { - this.handleStateChange(this._initialAuthState, null); - }) - .catch(err => this.error(err)); - } - }); - } - - render() { - const { authState, authData } = this.state; - const theme = this.props.theme || AmplifyTheme; - const messageMap = this.props.errorMessage || AmplifyMessageMap; - - const { hideDefault, signUpConfig, usernameAttributes } = this.props; - const props_children = this.props.children || []; - const default_children = [ - , - , - , - , - , - , - , - , - - ]; - const children = (hideDefault? [] : default_children) - .concat(props_children) - .map((child, index) => { - return React.cloneElement(child, { - key: 'auth_piece_' + index, - theme: theme, - messageMap: messageMap, - authState: authState, - authData: authData, - onStateChange: this.handleStateChange, - Auth: new AuthDecorator(this.handleStateChange), - usernameAttributes - }); - }); - return ( - - - {children} - - ); - } + constructor(props) { + super(props); + this._initialAuthState = this.props.authState || 'signIn'; + this.state = { + authState: props.authState || 'loading', + authData: props.authData, + }; + + this.handleStateChange = this.handleStateChange.bind(this); + this.checkUser = this.checkUser.bind(this); + this.onHubCapsule = this.onHubCapsule.bind(this); + this.checkContact = this.checkContact.bind(this); + + Hub.listen('auth', this.onHubCapsule); + } + + componentDidMount() { + this._isMounted = true; + this.checkUser(); + } + + componentWillUnmount() { + this._isMounted = false; + } + + onHubCapsule(capsule) { + const { channel, payload, source } = capsule; + if (channel === 'auth') { + this.checkUser(); + } + } + + handleStateChange(state, data) { + logger.debug('authenticator state change ' + state); + if (!this._isMounted) return; + if (state === this.state.authState) { + return; + } + + if (state === 'signedOut') { + state = 'signIn'; + } + this.setState({ authState: state, authData: data, error: null }); + if (this.props.onStateChange) { + this.props.onStateChange(state, data); + } + + switch (state) { + case 'signedIn': + Analytics.record('_userauth.sign_in'); + break; + case 'signedUp': + Analytics.record('_userauth.sign_up'); + break; + } + } + + async checkContact(user) { + try { + const data = await Auth.verifiedContact(user); + logger.debug('verified user attributes', data); + if (!JS.isEmpty(data.verified)) { + this.handleStateChange('signedIn', user); + } else { + user = Object.assign(user, data); + this.handleStateChange('verifyContact', user); + } + } catch (e) { + logger.warn('Failed to verify contact', e); + this.handleStateChange('signedIn', user); + } + } + + checkUser() { + const { authState } = this.state; + const statesJumpToSignIn = ['signedIn', 'signedOut', 'loading']; + Auth.currentAuthenticatedUser() + .then(user => { + if (!this._isMounted) return; + if (user) { + this.checkContact(user); + } else { + if (statesJumpToSignIn.includes(authState)) { + this.handleStateChange(this._initialAuthState, null); + } + } + }) + .catch(err => { + if (!this._isMounted) return; + logger.debug(err); + if (statesJumpToSignIn.includes(authState)) { + Auth.signOut() + .then(() => { + this.handleStateChange(this._initialAuthState, null); + }) + .catch(err => this.error(err)); + } + }); + } + + render() { + const { authState, authData } = this.state; + const theme = this.props.theme || AmplifyTheme; + const messageMap = this.props.errorMessage || AmplifyMessageMap; + + const { hideDefault, signUpConfig, usernameAttributes } = this.props; + const props_children = this.props.children || []; + const default_children = [ + , + , + , + , + , + , + , + , + , + ]; + const children = (hideDefault ? [] : default_children) + .concat(props_children) + .map((child, index) => { + return React.cloneElement(child, { + key: 'auth_piece_' + index, + theme: theme, + messageMap: messageMap, + authState: authState, + authData: authData, + onStateChange: this.handleStateChange, + Auth: new AuthDecorator(this.handleStateChange), + usernameAttributes, + }); + }); + return {children}; + } } diff --git a/packages/aws-amplify-react-native/src/Auth/ConfirmSignIn.js b/packages/aws-amplify-react-native/src/Auth/ConfirmSignIn.js index 06d9b1bfdaf..ffae109a23d 100644 --- a/packages/aws-amplify-react-native/src/Auth/ConfirmSignIn.js +++ b/packages/aws-amplify-react-native/src/Auth/ConfirmSignIn.js @@ -12,79 +12,70 @@ */ import React from 'react'; -import { - View, - TouchableWithoutFeedback, - Keyboard -} from 'react-native'; +import { View, TouchableWithoutFeedback, Keyboard } from 'react-native'; +import { Auth, I18n, Logger, JS } from 'aws-amplify'; import { - Auth, - I18n, - Logger, - JS -} from 'aws-amplify'; -import { - AmplifyButton, - FormField, - LinkCell, - Header, - ErrorRow + AmplifyButton, + FormField, + LinkCell, + Header, + ErrorRow, } from '../AmplifyUI'; import AuthPiece from './AuthPiece'; const logger = new Logger('ConfirmSignIn'); export default class ConfirmSignIn extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this._validAuthStates = ['confirmSignIn']; - this.state = { - code: null, - error: null - } + this._validAuthStates = ['confirmSignIn']; + this.state = { + code: null, + error: null, + }; - this.confirm = this.confirm.bind(this); - this.checkContact = this.checkContact.bind(this); - } + this.confirm = this.confirm.bind(this); + this.checkContact = this.checkContact.bind(this); + } - confirm() { - const user = this.props.authData; - const { code } = this.state; - logger.debug('Confirm Sign In for ' + user.username); - Auth.confirmSignIn(user, code) - .then(data => this.checkContact(user)) - .catch(err => this.error(err)); - } + confirm() { + const user = this.props.authData; + const { code } = this.state; + logger.debug('Confirm Sign In for ' + user.username); + Auth.confirmSignIn(user, code) + .then(data => this.checkContact(user)) + .catch(err => this.error(err)); + } - showComponent(theme) { - return ( - - -
{I18n.get('Confirm Sign In')}
- - this.setState({ code: text })} - label={I18n.get('Confirmation Code')} - placeholder={I18n.get('Enter your confirmation code')} - required={true} - /> - - - - this.changeState('signIn')}> - {I18n.get('Back to Sign In')} - - - {this.state.error} -
-
- ); - } + showComponent(theme) { + return ( + + +
{I18n.get('Confirm Sign In')}
+ + this.setState({ code: text })} + label={I18n.get('Confirmation Code')} + placeholder={I18n.get('Enter your confirmation code')} + required={true} + /> + + + + this.changeState('signIn')}> + {I18n.get('Back to Sign In')} + + + {this.state.error} +
+
+ ); + } } diff --git a/packages/aws-amplify-react-native/src/Auth/ConfirmSignUp.js b/packages/aws-amplify-react-native/src/Auth/ConfirmSignUp.js index 908d8b17a2f..601c82b7880 100644 --- a/packages/aws-amplify-react-native/src/Auth/ConfirmSignUp.js +++ b/packages/aws-amplify-react-native/src/Auth/ConfirmSignUp.js @@ -12,102 +12,100 @@ */ import React from 'react'; -import { - View, - TouchableWithoutFeedback, - Keyboard -} from 'react-native'; +import { View, TouchableWithoutFeedback, Keyboard } from 'react-native'; +import { Auth, I18n, Logger } from 'aws-amplify'; import { - Auth, - I18n, - Logger -} from 'aws-amplify'; -import { - FormField, - LinkCell, - Header, - ErrorRow, - AmplifyButton + FormField, + LinkCell, + Header, + ErrorRow, + AmplifyButton, } from '../AmplifyUI'; import AuthPiece from './AuthPiece'; const logger = new Logger('ConfirmSignUp'); export default class ConfirmSignUp extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this._validAuthStates = ['confirmSignUp']; - this.state = { - username: null, - code: null, - error: null - } + this._validAuthStates = ['confirmSignUp']; + this.state = { + username: null, + code: null, + error: null, + }; - this.confirm = this.confirm.bind(this); - this.resend = this.resend.bind(this); - } + this.confirm = this.confirm.bind(this); + this.resend = this.resend.bind(this); + } - confirm() { - const { username, code } = this.state; - logger.debug('Confirm Sign Up for ' + username); - Auth.confirmSignUp(username, code) - .then(data => this.changeState('signedUp')) - .catch(err => this.error(err)); - } + confirm() { + const { username, code } = this.state; + logger.debug('Confirm Sign Up for ' + username); + Auth.confirmSignUp(username, code) + .then(data => this.changeState('signedUp')) + .catch(err => this.error(err)); + } - resend() { - const { username } = this.state; - logger.debug('Resend Sign Up for ' + username); - Auth.resendSignUp(username) - .then(() => logger.debug('code sent')) - .catch(err => this.error(err)); - } + resend() { + const { username } = this.state; + logger.debug('Resend Sign Up for ' + username); + Auth.resendSignUp(username) + .then(() => logger.debug('code sent')) + .catch(err => this.error(err)); + } - componentWillReceiveProps(nextProps) { - const username = nextProps.authData; - if (username && !this.state.username) { this.setState({ username }); } - } + componentWillReceiveProps(nextProps) { + const username = nextProps.authData; + if (username && !this.state.username) { + this.setState({ username }); + } + } - showComponent(theme) { - return ( - - -
{I18n.get('Confirm Sign Up')}
- - this.setState({ username: text })} - label={I18n.get(this.getUsernameLabel())} - placeholder={I18n.get('Enter your username')} - required={true} - value={this.state.username} - /> - this.setState({ code: text })} - label={I18n.get('Confirmation Code')} - placeholder={I18n.get('Enter your confirmation code')} - required={true} - /> - - - - - {I18n.get('Resend code')} - - this.changeState('signIn')}> - {I18n.get('Back to Sign In')} - - - {this.state.error} -
-
- ); - } + showComponent(theme) { + return ( + + +
{I18n.get('Confirm Sign Up')}
+ + this.setState({ username: text })} + label={I18n.get(this.getUsernameLabel())} + placeholder={I18n.get('Enter your username')} + required={true} + value={this.state.username} + /> + this.setState({ code: text })} + label={I18n.get('Confirmation Code')} + placeholder={I18n.get('Enter your confirmation code')} + required={true} + /> + + + + + {I18n.get('Resend code')} + + this.changeState('signIn')}> + {I18n.get('Back to Sign In')} + + + {this.state.error} +
+
+ ); + } } diff --git a/packages/aws-amplify-react-native/src/Auth/ForgotPassword.js b/packages/aws-amplify-react-native/src/Auth/ForgotPassword.js index 184245499df..1b59c3198df 100644 --- a/packages/aws-amplify-react-native/src/Auth/ForgotPassword.js +++ b/packages/aws-amplify-react-native/src/Auth/ForgotPassword.js @@ -12,122 +12,114 @@ */ import React from 'react'; -import { - View, - TouchableWithoutFeedback, - Keyboard -} from 'react-native'; +import { View, TouchableWithoutFeedback, Keyboard } from 'react-native'; +import { Auth, I18n, Logger } from 'aws-amplify'; import { - Auth, - I18n, - Logger -} from 'aws-amplify'; -import { - FormField, - AmplifyButton, - LinkCell, - Header, - ErrorRow + FormField, + AmplifyButton, + LinkCell, + Header, + ErrorRow, } from '../AmplifyUI'; import AuthPiece from './AuthPiece'; const logger = new Logger('ForgotPassword'); export default class ForgotPassword extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this._validAuthStates = ['forgotPassword']; - this.state = { delivery: null }; + this._validAuthStates = ['forgotPassword']; + this.state = { delivery: null }; - this.send = this.send.bind(this); - this.submit = this.submit.bind(this); - } + this.send = this.send.bind(this); + this.submit = this.submit.bind(this); + } - send() { - const username = this.getUsernameFromInput(); - if (!username) { - this.error('Username cannot be empty'); - return; - } - Auth.forgotPassword(username) - .then(data => { - logger.debug(data) - this.setState({ delivery: data.CodeDeliveryDetails }); - }) - .catch(err => this.error(err)); - } + send() { + const username = this.getUsernameFromInput(); + if (!username) { + this.error('Username cannot be empty'); + return; + } + Auth.forgotPassword(username) + .then(data => { + logger.debug(data); + this.setState({ delivery: data.CodeDeliveryDetails }); + }) + .catch(err => this.error(err)); + } - submit() { - const { code, password } = this.state; - const username = this.getUsernameFromInput(); - Auth.forgotPasswordSubmit(username, code, password) - .then(data => { - logger.debug(data); - this.changeState('signIn'); - }) - .catch(err => this.error(err)); - } + submit() { + const { code, password } = this.state; + const username = this.getUsernameFromInput(); + Auth.forgotPasswordSubmit(username, code, password) + .then(data => { + logger.debug(data); + this.changeState('signIn'); + }) + .catch(err => this.error(err)); + } - forgotBody(theme) { - return ( - - {this.renderUsernameField(theme)} - - - ) - } + forgotBody(theme) { + return ( + + {this.renderUsernameField(theme)} + + + ); + } - submitBody(theme) { - return ( - - this.setState({ code: text })} - label={I18n.get('Confirmation Code')} - placeholder={I18n.get('Enter your confirmation code')} - required={true} - /> - this.setState({ password: text })} - label={I18n.get('Password')} - placeholder={I18n.get('Enter your new password')} - secureTextEntry={true} - required={true} - /> - - - ) - } + submitBody(theme) { + return ( + + this.setState({ code: text })} + label={I18n.get('Confirmation Code')} + placeholder={I18n.get('Enter your confirmation code')} + required={true} + /> + this.setState({ password: text })} + label={I18n.get('Password')} + placeholder={I18n.get('Enter your new password')} + secureTextEntry={true} + required={true} + /> + + + ); + } - showComponent(theme) { - return ( - - -
{I18n.get('Forgot Password')}
- - { !this.state.delivery && this.forgotBody(theme) } - { this.state.delivery && this.submitBody(theme) } - - - this.changeState('signIn')}> - {I18n.get('Back to Sign In')} - - - {this.state.error} -
-
- ) - } + showComponent(theme) { + return ( + + +
{I18n.get('Forgot Password')}
+ + {!this.state.delivery && this.forgotBody(theme)} + {this.state.delivery && this.submitBody(theme)} + + + this.changeState('signIn')}> + {I18n.get('Back to Sign In')} + + + {this.state.error} +
+
+ ); + } } diff --git a/packages/aws-amplify-react-native/src/Auth/Greetings.js b/packages/aws-amplify-react-native/src/Auth/Greetings.js index 44c63cd7f90..0bf88e4f8ae 100644 --- a/packages/aws-amplify-react-native/src/Auth/Greetings.js +++ b/packages/aws-amplify-react-native/src/Auth/Greetings.js @@ -12,16 +12,8 @@ */ import React from 'react'; -import { - View, - Text, - Button -} from 'react-native'; -import { - Auth, - I18n, - Logger -} from 'aws-amplify'; +import { View, Text, Button } from 'react-native'; +import { Auth, I18n, Logger } from 'aws-amplify'; import { AmplifyButton } from '../AmplifyUI'; import AmplifyTheme from '../AmplifyTheme'; import AuthPiece from './AuthPiece'; @@ -29,63 +21,64 @@ import AuthPiece from './AuthPiece'; const logger = new Logger('Greetings'); export default class Greetings extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.signOut = this.signOut.bind(this); - } + this.signOut = this.signOut.bind(this); + } - signOut() { - Auth.signOut() - .then(() => this.changeState('signedOut')) - .catch(err => this.error(err)); - } + signOut() { + Auth.signOut() + .then(() => this.changeState('signedOut')) + .catch(err => this.error(err)); + } - render() { - const { authState, authData } = this.props; - const signedIn = (authState === 'signedIn'); - const theme = this.props.theme || AmplifyTheme; + render() { + const { authState, authData } = this.props; + const signedIn = authState === 'signedIn'; + const theme = this.props.theme || AmplifyTheme; - let defaultMessage = ""; - const user = authData; - if (user) { - const { usernameAttributes = [] } = this.props; - let name = ''; - if (usernameAttributes === 'email') { - // Email as Username - name = user.attributes? user.attributes.email : user.username; - defaultMessage = `${name}`; - } else if (usernameAttributes === 'phone_number') { - // Phone number as Username - name = user.attributes? user.attributes.phone_number : user.username; - defaultMessage = `${name}`; - } else { - name = user.username || "unknown user"; - defaultMessage = `${I18n.get('Hello')} ${name}`; - } - } + let defaultMessage = ''; + const user = authData; + if (user) { + const { usernameAttributes = [] } = this.props; + let name = ''; + if (usernameAttributes === 'email') { + // Email as Username + name = user.attributes ? user.attributes.email : user.username; + defaultMessage = `${name}`; + } else if (usernameAttributes === 'phone_number') { + // Phone number as Username + name = user.attributes ? user.attributes.phone_number : user.username; + defaultMessage = `${name}`; + } else { + name = user.username || 'unknown user'; + defaultMessage = `${I18n.get('Hello')} ${name}`; + } + } - let message; - if (signedIn) { - message = this.props.signedInMessage || defaultMessage; - } else { - message = this.props.signedOutMessage || I18n.get("Please Sign In / Sign Up"); - } + let message; + if (signedIn) { + message = this.props.signedInMessage || defaultMessage; + } else { + message = + this.props.signedOutMessage || I18n.get('Please Sign In / Sign Up'); + } - const content = signedIn ? ( - - {message} - - - ) : ( - {message} - ); + const content = signedIn ? ( + + {message} + + + ) : ( + {message} + ); - return content; - } + return content; + } } diff --git a/packages/aws-amplify-react-native/src/Auth/Loading.js b/packages/aws-amplify-react-native/src/Auth/Loading.js index 9162a319460..94960780adb 100644 --- a/packages/aws-amplify-react-native/src/Auth/Loading.js +++ b/packages/aws-amplify-react-native/src/Auth/Loading.js @@ -18,17 +18,17 @@ import AuthPiece from './AuthPiece'; import { Header } from '../AmplifyUI'; export default class Loading extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this._validAuthStates = ['loading']; - } + this._validAuthStates = ['loading']; + } - showComponent(theme) { - return ( - -
{I18n.get('Loading...')}
-
- ); - } -} \ No newline at end of file + showComponent(theme) { + return ( + +
{I18n.get('Loading...')}
+
+ ); + } +} diff --git a/packages/aws-amplify-react-native/src/Auth/RequireNewPassword.js b/packages/aws-amplify-react-native/src/Auth/RequireNewPassword.js index 07337a0981c..8d7ff02ea96 100644 --- a/packages/aws-amplify-react-native/src/Auth/RequireNewPassword.js +++ b/packages/aws-amplify-react-native/src/Auth/RequireNewPassword.js @@ -13,118 +13,118 @@ import React from 'react'; import { - View, - TouchableWithoutFeedback, - Keyboard, - ScrollView + View, + TouchableWithoutFeedback, + Keyboard, + ScrollView, } from 'react-native'; +import { Auth, I18n, Logger } from 'aws-amplify'; import { - Auth, - I18n, - Logger -} from 'aws-amplify'; -import { - FormField, - AmplifyButton, - LinkCell, - Header, - ErrorRow + FormField, + AmplifyButton, + LinkCell, + Header, + ErrorRow, } from '../AmplifyUI'; import AuthPiece from './AuthPiece'; const logger = new Logger('RequireNewPassword'); export default class RequireNewPassword extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); + + this._validAuthStates = ['requireNewPassword']; + this.state = { + password: null, + error: null, + requiredAttributes: {}, + }; - this._validAuthStates = ['requireNewPassword']; - this.state = { - password: null, - error: null, - requiredAttributes: {} - } + this.change = this.change.bind(this); + } - this.change = this.change.bind(this); - } - - change() { - const user = this.props.authData; - const { password, requiredAttributes } = this.state; - logger.debug('Require new password for ' + user.username); - Auth.completeNewPassword(user, password, requiredAttributes) - .then(user => { - if (user.challengeName === 'SMS_MFA') { - this.changeState('confirmSignIn', user); - } else { - this.checkContact(user); - } - }) - .catch(err => this.error(err)); - } + change() { + const user = this.props.authData; + const { password, requiredAttributes } = this.state; + logger.debug('Require new password for ' + user.username); + Auth.completeNewPassword(user, password, requiredAttributes) + .then(user => { + if (user.challengeName === 'SMS_MFA') { + this.changeState('confirmSignIn', user); + } else { + this.checkContact(user); + } + }) + .catch(err => this.error(err)); + } - generateForm(attribute, theme){ - return ( - { - const attributes = this.state.requiredAttributes; - if (text !== '') attributes[attribute] = text; - else delete attributes[attribute]; - this.setState({ requiredAttributes: attributes }); - } - } - label={I18n.get(convertToPlaceholder(attribute))} - key={I18n.get(convertToPlaceholder(attribute))} - placeholder={I18n.get(convertToPlaceholder(attribute))} - required={true} - /> - ); - } + generateForm(attribute, theme) { + return ( + { + const attributes = this.state.requiredAttributes; + if (text !== '') attributes[attribute] = text; + else delete attributes[attribute]; + this.setState({ requiredAttributes: attributes }); + }} + label={I18n.get(convertToPlaceholder(attribute))} + key={I18n.get(convertToPlaceholder(attribute))} + placeholder={I18n.get(convertToPlaceholder(attribute))} + required={true} + /> + ); + } - showComponent(theme) { - const user = this.props.authData; - const { requiredAttributes } = user.challengeParam; - return ( - - -
{I18n.get('Change Password')}
- - this.setState({ password: text })} - label={I18n.get('Password')} - placeholder={I18n.get('Enter your password')} - secureTextEntry={true} - required={true} - /> - {requiredAttributes - .map(attribute => { - logger.debug('attributes', attribute); - return this.generateForm(attribute, theme); - } - )} - - - - this.changeState('signIn')}> - {I18n.get('Back to Sign In')} - - - {this.state.error} -
-
- ); - } + showComponent(theme) { + const user = this.props.authData; + const { requiredAttributes } = user.challengeParam; + return ( + + +
{I18n.get('Change Password')}
+ + this.setState({ password: text })} + label={I18n.get('Password')} + placeholder={I18n.get('Enter your password')} + secureTextEntry={true} + required={true} + /> + {requiredAttributes.map(attribute => { + logger.debug('attributes', attribute); + return this.generateForm(attribute, theme); + })} + + + + this.changeState('signIn')}> + {I18n.get('Back to Sign In')} + + + {this.state.error} +
+
+ ); + } } function convertToPlaceholder(str) { - return str.split('_').map(part => part.charAt(0).toUpperCase() + part.substr(1).toLowerCase()).join(' ') -} \ No newline at end of file + return str + .split('_') + .map(part => part.charAt(0).toUpperCase() + part.substr(1).toLowerCase()) + .join(' '); +} diff --git a/packages/aws-amplify-react-native/src/Auth/SignIn.js b/packages/aws-amplify-react-native/src/Auth/SignIn.js index 3f64d9cee5a..650066a9747 100644 --- a/packages/aws-amplify-react-native/src/Auth/SignIn.js +++ b/packages/aws-amplify-react-native/src/Auth/SignIn.js @@ -12,96 +12,90 @@ */ import React from 'react'; -import { - View, - TouchableWithoutFeedback, - Keyboard -} from 'react-native'; -import { - Auth, - I18n, - Logger, - JS -} from 'aws-amplify'; +import { View, TouchableWithoutFeedback, Keyboard } from 'react-native'; +import { Auth, I18n, Logger, JS } from 'aws-amplify'; import AuthPiece from './AuthPiece'; import { - AmplifyButton, - FormField, - LinkCell, - Header, - ErrorRow + AmplifyButton, + FormField, + LinkCell, + Header, + ErrorRow, } from '../AmplifyUI'; const logger = new Logger('SignIn'); export default class SignIn extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this._validAuthStates = ['signIn', 'signedOut', 'signedUp']; - this.state = { - username: null, - password: null, - error: null - } + this._validAuthStates = ['signIn', 'signedOut', 'signedUp']; + this.state = { + username: null, + password: null, + error: null, + }; - this.checkContact = this.checkContact.bind(this); - this.signIn = this.signIn.bind(this); - } + this.checkContact = this.checkContact.bind(this); + this.signIn = this.signIn.bind(this); + } - signIn() { - const username = this.getUsernameFromInput() || ''; - const { password } = this.state; - logger.debug('Sign In for ' + username); - Auth.signIn(username, password) - .then(user => { - logger.debug(user); - const requireMFA = (user.Session !== null); - if (user.challengeName === 'SMS_MFA') { - this.changeState('confirmSignIn', user); - } else if (user.challengeName === 'NEW_PASSWORD_REQUIRED') { - logger.debug('require new password', user.challengeParam); - this.changeState('requireNewPassword', user); - } else { - this.checkContact(user); - } - }) - .catch(err => this.error(err)); - } + signIn() { + const username = this.getUsernameFromInput() || ''; + const { password } = this.state; + logger.debug('Sign In for ' + username); + Auth.signIn(username, password) + .then(user => { + logger.debug(user); + const requireMFA = user.Session !== null; + if (user.challengeName === 'SMS_MFA') { + this.changeState('confirmSignIn', user); + } else if (user.challengeName === 'NEW_PASSWORD_REQUIRED') { + logger.debug('require new password', user.challengeParam); + this.changeState('requireNewPassword', user); + } else { + this.checkContact(user); + } + }) + .catch(err => this.error(err)); + } - showComponent(theme) { - return ( - - -
{I18n.get('Sign in to your account')}
- - {this.renderUsernameField(theme)} - this.setState({ password: text })} - label={I18n.get('Password')} - placeholder={I18n.get('Enter your password')} - secureTextEntry={true} - required={true} - /> - - - - this.changeState('forgotPassword')}> - {I18n.get('Forgot Password')} - - this.changeState('signUp')}> - {I18n.get('Sign Up')} - - - {this.state.error} -
-
- ); - } + showComponent(theme) { + return ( + + +
{I18n.get('Sign in to your account')}
+ + {this.renderUsernameField(theme)} + this.setState({ password: text })} + label={I18n.get('Password')} + placeholder={I18n.get('Enter your password')} + secureTextEntry={true} + required={true} + /> + + + + this.changeState('forgotPassword')} + > + {I18n.get('Forgot Password')} + + this.changeState('signUp')}> + {I18n.get('Sign Up')} + + + {this.state.error} +
+
+ ); + } } diff --git a/packages/aws-amplify-react-native/src/Auth/SignUp.js b/packages/aws-amplify-react-native/src/Auth/SignUp.js index 1d342dbe1d6..1b7537c4c70 100644 --- a/packages/aws-amplify-react-native/src/Auth/SignUp.js +++ b/packages/aws-amplify-react-native/src/Auth/SignUp.js @@ -13,257 +13,273 @@ import React from 'react'; import { - View, - Text, - TextInput, - Button, - TouchableWithoutFeedback, - Keyboard, - Picker, - ScrollView + View, + Text, + TextInput, + Button, + TouchableWithoutFeedback, + Keyboard, + Picker, + ScrollView, } from 'react-native'; +import { Auth, I18n, Logger } from 'aws-amplify'; import { - Auth, - I18n, - Logger -} from 'aws-amplify'; -import { - FormField, - PhoneField, - LinkCell, - Header, - ErrorRow, - AmplifyButton + FormField, + PhoneField, + LinkCell, + Header, + ErrorRow, + AmplifyButton, } from '../AmplifyUI'; import AuthPiece from './AuthPiece'; import countryDialCodes from '../CountryDialCodes'; -import signUpWithUsernameFields, { signUpWithEmailFields, signUpWithPhoneNumberFields } from './common/default-sign-up-fields' - +import signUpWithUsernameFields, { + signUpWithEmailFields, + signUpWithPhoneNumberFields, +} from './common/default-sign-up-fields'; const logger = new Logger('SignUp'); export default class SignUp extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this._validAuthStates = ['signUp']; - this.state = {}; - this.signUp = this.signUp.bind(this); - this.sortFields = this.sortFields.bind(this); - this.getDefaultDialCode = this.getDefaultDialCode.bind(this); - this.checkCustomSignUpFields = this.checkCustomSignUpFields.bind(this); - this.needPrefix = this.needPrefix.bind(this); - this.header = (this.props && - this.props.signUpConfig && - this.props.signUpConfig.header) ? this.props.signUpConfig.header : 'Create a new account'; - - const { usernameAttributes='username' }= this.props; - if (usernameAttributes === 'email') { - this.defaultSignUpFields = signUpWithEmailFields; - } else if (usernameAttributes === 'phone_number') { - this.defaultSignUpFields = signUpWithPhoneNumberFields; - } else { - this.defaultSignUpFields = signUpWithUsernameFields; - } - } + this._validAuthStates = ['signUp']; + this.state = {}; + this.signUp = this.signUp.bind(this); + this.sortFields = this.sortFields.bind(this); + this.getDefaultDialCode = this.getDefaultDialCode.bind(this); + this.checkCustomSignUpFields = this.checkCustomSignUpFields.bind(this); + this.needPrefix = this.needPrefix.bind(this); + this.header = + this.props && this.props.signUpConfig && this.props.signUpConfig.header + ? this.props.signUpConfig.header + : 'Create a new account'; - isValid() { - for (const el in this.signUpFields) { - if (el.required && !this.state[el.key]) return false; - } - return true; - } + const { usernameAttributes = 'username' } = this.props; + if (usernameAttributes === 'email') { + this.defaultSignUpFields = signUpWithEmailFields; + } else if (usernameAttributes === 'phone_number') { + this.defaultSignUpFields = signUpWithPhoneNumberFields; + } else { + this.defaultSignUpFields = signUpWithUsernameFields; + } + } - sortFields() { + isValid() { + for (const el in this.signUpFields) { + if (el.required && !this.state[el.key]) return false; + } + return true; + } - if (this.props.signUpConfig && this.props.signUpConfig.hiddenDefaults && this.props.signUpConfig.hiddenDefaults.length > 0){ - this.defaultSignUpFields = this.defaultSignUpFields.filter((d) => { - return !this.props.signUpConfig.hiddenDefaults.includes(d.key); - }); - } + sortFields() { + if ( + this.props.signUpConfig && + this.props.signUpConfig.hiddenDefaults && + this.props.signUpConfig.hiddenDefaults.length > 0 + ) { + this.defaultSignUpFields = this.defaultSignUpFields.filter(d => { + return !this.props.signUpConfig.hiddenDefaults.includes(d.key); + }); + } - if (this.checkCustomSignUpFields()) { + if (this.checkCustomSignUpFields()) { + if ( + !this.props.signUpConfig || + !this.props.signUpConfig.hideAllDefaults + ) { + // see if fields passed to component should override defaults + this.defaultSignUpFields.forEach((f, i) => { + const matchKey = this.signUpFields.findIndex(d => { + return d.key === f.key; + }); + if (matchKey === -1) { + this.signUpFields.push(f); + } + }); + } - if (!this.props.signUpConfig || !this.props.signUpConfig.hideAllDefaults) { - // see if fields passed to component should override defaults - this.defaultSignUpFields.forEach((f, i) => { - const matchKey = this.signUpFields.findIndex((d) => { - return d.key === f.key; - }); - if (matchKey === -1) { - this.signUpFields.push(f); - } - }); - } - - /* + /* sort fields based on following rules: 1. Fields with displayOrder are sorted before those without displayOrder 2. Fields with conflicting displayOrder are sorted alphabetically by key 3. Fields without displayOrder are sorted alphabetically by key */ - this.signUpFields.sort((a, b) => { - if (a.displayOrder && b.displayOrder) { - if (a.displayOrder < b.displayOrder) { - return -1; - } else if (a.displayOrder > b.displayOrder) { - return 1; - } else { - if (a.key < b.key) { - return -1; - } else { - return 1; - } - } - } else if (!a.displayOrder && b.displayOrder) { - return 1; - } else if (a.displayOrder && !b.displayOrder) { - return -1; - } else if (!a.displayOrder && !b.displayOrder) { - if (a.key < b.key) { - return -1; - } else { - return 1; - } - } - }); - } else { - this.signUpFields = this.defaultSignUpFields; - } - } - - needPrefix(key) { - const field = this.signUpFields.find(e => e.key === key); - if (key.indexOf('custom:') !== 0) { - return field.custom ; - } else if (key.indexOf('custom:') === 0 && field.custom === false) { - logger.warn('Custom prefix prepended to key but custom field flag is set to false'); - } - return null; - } - - getDefaultDialCode() { - return this.props.signUpConfig && - this.props.signUpConfig.defaultCountryCode && - countryDialCodes.indexOf(`+${this.props.signUpConfig.defaultCountryCode}`) !== '-1' ? - `+${this.props.signUpConfig.defaultCountryCode}` : - "+1" - } + this.signUpFields.sort((a, b) => { + if (a.displayOrder && b.displayOrder) { + if (a.displayOrder < b.displayOrder) { + return -1; + } else if (a.displayOrder > b.displayOrder) { + return 1; + } else { + if (a.key < b.key) { + return -1; + } else { + return 1; + } + } + } else if (!a.displayOrder && b.displayOrder) { + return 1; + } else if (a.displayOrder && !b.displayOrder) { + return -1; + } else if (!a.displayOrder && !b.displayOrder) { + if (a.key < b.key) { + return -1; + } else { + return 1; + } + } + }); + } else { + this.signUpFields = this.defaultSignUpFields; + } + } - checkCustomSignUpFields() { - return this.props.signUpConfig && - this.props.signUpConfig.signUpFields && - this.props.signUpConfig.signUpFields.length > 0 - } + needPrefix(key) { + const field = this.signUpFields.find(e => e.key === key); + if (key.indexOf('custom:') !== 0) { + return field.custom; + } else if (key.indexOf('custom:') === 0 && field.custom === false) { + logger.warn( + 'Custom prefix prepended to key but custom field flag is set to false' + ); + } + return null; + } - signUp() { - if (!Auth || typeof Auth.signUp !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } + getDefaultDialCode() { + return this.props.signUpConfig && + this.props.signUpConfig.defaultCountryCode && + countryDialCodes.indexOf( + `+${this.props.signUpConfig.defaultCountryCode}` + ) !== '-1' + ? `+${this.props.signUpConfig.defaultCountryCode}` + : '+1'; + } - const signup_info = { - username: this.state.username, - password: this.state.password, - attributes: { - - } - }; + checkCustomSignUpFields() { + return ( + this.props.signUpConfig && + this.props.signUpConfig.signUpFields && + this.props.signUpConfig.signUpFields.length > 0 + ); + } - const inputKeys = Object.keys(this.state); - const inputVals = Object.values(this.state); + signUp() { + if (!Auth || typeof Auth.signUp !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } - inputKeys.forEach((key, index) => { - if (!['username', 'password', 'checkedValue'].includes(key)) { - if (key !== 'phone_line_number' && key !== 'dial_code' && key !== 'error') { - const newKey = `${this.needPrefix(key) ? 'custom:' : ''}${key}`; - signup_info.attributes[newKey] = inputVals[index]; - } - } - }); + const signup_info = { + username: this.state.username, + password: this.state.password, + attributes: {}, + }; - let labelCheck = false; - this.signUpFields.forEach(field => { - if (field.label === this.getUsernameLabel()) { - logger.debug(`Changing the username to the value of ${field.label}`); - signup_info.username = signup_info.attributes[field.key] || signup_info.username; - labelCheck = true; - } - }); - if (!labelCheck && !signup_info.username){ - // if the customer customized the username field in the sign up form - // He needs to either set the key of that field to 'username' - // Or make the label of the field the same as the 'usernameAttributes' - throw new Error(`Couldn't find the label: ${this.getUsernameLabel()}, in sign up fields according to usernameAttributes!`); - } + const inputKeys = Object.keys(this.state); + const inputVals = Object.values(this.state); - logger.debug('Signing up with', signup_info); - Auth.signUp(signup_info).then((data) => { - this.changeState('confirmSignUp', data.user.username) - }) - .catch(err => this.error(err)); - } + inputKeys.forEach((key, index) => { + if (!['username', 'password', 'checkedValue'].includes(key)) { + if ( + key !== 'phone_line_number' && + key !== 'dial_code' && + key !== 'error' + ) { + const newKey = `${this.needPrefix(key) ? 'custom:' : ''}${key}`; + signup_info.attributes[newKey] = inputVals[index]; + } + } + }); - showComponent(theme) { - if (this.checkCustomSignUpFields()) { - this.signUpFields = this.props.signUpConfig.signUpFields; - } - this.sortFields(); - return ( - - -
{I18n.get(this.header)}
- - { - this.signUpFields.map((field) => { - return field.key !== 'phone_number' ? ( - { - const stateObj = this.state; - stateObj[field.key] = text; - this.setState(stateObj) - } - } - label={I18n.get(field.label)} - placeholder={I18n.get(field.placeholder)} - required={field.required} - /> - ) : ( - this.setState({ phone_number: text })} - label={I18n.get(field.label)} - placeholder={I18n.get(field.placeholder)} - keyboardType="phone-pad" - required={field.required} - defaultDialCode={this.getDefaultDialCode()} - /> - ) - }) - } - - - - this.changeState('confirmSignUp')}> - {I18n.get('Confirm a Code')} - - this.changeState('signIn')}> - {I18n.get('Sign In')} - - - {this.state.error} -
-
- ); - } + let labelCheck = false; + this.signUpFields.forEach(field => { + if (field.label === this.getUsernameLabel()) { + logger.debug(`Changing the username to the value of ${field.label}`); + signup_info.username = + signup_info.attributes[field.key] || signup_info.username; + labelCheck = true; + } + }); + if (!labelCheck && !signup_info.username) { + // if the customer customized the username field in the sign up form + // He needs to either set the key of that field to 'username' + // Or make the label of the field the same as the 'usernameAttributes' + throw new Error( + `Couldn't find the label: ${this.getUsernameLabel()}, in sign up fields according to usernameAttributes!` + ); + } + logger.debug('Signing up with', signup_info); + Auth.signUp(signup_info) + .then(data => { + this.changeState('confirmSignUp', data.user.username); + }) + .catch(err => this.error(err)); + } + showComponent(theme) { + if (this.checkCustomSignUpFields()) { + this.signUpFields = this.props.signUpConfig.signUpFields; + } + this.sortFields(); + return ( + + +
{I18n.get(this.header)}
+ + {this.signUpFields.map(field => { + return field.key !== 'phone_number' ? ( + { + const stateObj = this.state; + stateObj[field.key] = text; + this.setState(stateObj); + }} + label={I18n.get(field.label)} + placeholder={I18n.get(field.placeholder)} + required={field.required} + /> + ) : ( + this.setState({ phone_number: text })} + label={I18n.get(field.label)} + placeholder={I18n.get(field.placeholder)} + keyboardType="phone-pad" + required={field.required} + defaultDialCode={this.getDefaultDialCode()} + /> + ); + })} + + + + this.changeState('confirmSignUp')} + > + {I18n.get('Confirm a Code')} + + this.changeState('signIn')}> + {I18n.get('Sign In')} + + + {this.state.error} +
+
+ ); + } } diff --git a/packages/aws-amplify-react-native/src/Auth/VerifyContact.js b/packages/aws-amplify-react-native/src/Auth/VerifyContact.js index c9ffa5358d0..a55c0fba85e 100644 --- a/packages/aws-amplify-react-native/src/Auth/VerifyContact.js +++ b/packages/aws-amplify-react-native/src/Auth/VerifyContact.js @@ -12,192 +12,185 @@ */ import React from 'react'; -import { - View, - Picker, - TouchableWithoutFeedback, - Keyboard -} from 'react-native'; +import { View, Picker, TouchableWithoutFeedback, Keyboard } from 'react-native'; +import { Auth, I18n, Logger } from 'aws-amplify'; import { - Auth, - I18n, - Logger -} from 'aws-amplify'; -import { - AmplifyButton, - FormField, - LinkCell, - Header, - ErrorRow + AmplifyButton, + FormField, + LinkCell, + Header, + ErrorRow, } from '../AmplifyUI'; import AuthPiece from './AuthPiece'; const logger = new Logger('VerifyContact'); export default class VerifyContact extends AuthPiece { - constructor(props) { - super(props); - - this._validAuthStates = ['verifyContact']; - this.state = { - verifyAttr: null, - error: null - } - - this.verify = this.verify.bind(this); - this.submit = this.submit.bind(this); - } - - static getDerivedStateFromProps(props, state) { - if (props.authData) { - const { unverified } = props.authData; - if (!unverified) { - logger.debug('no unverified contact'); - return null; - } - - const { email, phone_number } = unverified; - if (email && !state.pickAttr) { - return { - pickAttr: 'email', - }; - } else if (phone_number && !state.pickAttr) { - return { - pickAttr: 'phone_number', - }; - } else { - return null; - } - - } else { - return null; - } - } - - verify() { - const user = this.props.authData; - const attr = this.state.pickAttr; - if (!attr) { - this.error('Neither Email nor Phone Number selected'); - return; - } - - const that = this; - Auth.verifyCurrentUserAttribute(attr) - .then(data => { - logger.debug(data); - that.setState({ verifyAttr: attr }); - }) - .catch(err => this.error(err)); - } - - submit() { - const attr = this.state.verifyAttr; - const { code } = this.state; - Auth.verifyCurrentUserAttributeSubmit(attr, code) - .then(data => { - logger.debug(data); - this.changeState('signedIn', this.props.authData); - }) - .catch(err => this.error(err)); - } - - skip() { - this.changeState('signedIn'); - } - - // Have to do it in this way to avoid null or undefined element in React.createElement() - createPicker(unverified) { - const { email, phone_number } = unverified; - if (email && phone_number) { - return ( - this.setState({pickAttr: value})} - > - - - - ); - } else if (email) { - return ( - this.setState({pickAttr: value})} - > - - - ); - } else if (phone_number) { - return ( - this.setState({pickAttr: value})} - > - - - ); - } else { - return null; - } - } - - verifyBody(theme) { - const { unverified } = this.props.authData; - if (!unverified) { - logger.debug('no unverified contact'); - return null; - } - - const { email, phone_number } = unverified; - return ( - - {this.createPicker(unverified)} - - - ) - } - - submitBody(theme) { - return ( - - this.setState({ code: text })} - label={I18n.get('Confirmation Code')} - placeholder={I18n.get('Enter your confirmation code')} - required={true} - /> - - - ) - } - - showComponent(theme) { - return ( - - -
{I18n.get('Verify Contact')}
- { !this.state.verifyAttr && this.verifyBody(theme) } - { this.state.verifyAttr && this.submitBody(theme) } - - this.changeState('signedIn')}> - {I18n.get('Skip')} - - - {this.state.error} -
-
- ); - } + constructor(props) { + super(props); + + this._validAuthStates = ['verifyContact']; + this.state = { + verifyAttr: null, + error: null, + }; + + this.verify = this.verify.bind(this); + this.submit = this.submit.bind(this); + } + + static getDerivedStateFromProps(props, state) { + if (props.authData) { + const { unverified } = props.authData; + if (!unverified) { + logger.debug('no unverified contact'); + return null; + } + + const { email, phone_number } = unverified; + if (email && !state.pickAttr) { + return { + pickAttr: 'email', + }; + } else if (phone_number && !state.pickAttr) { + return { + pickAttr: 'phone_number', + }; + } else { + return null; + } + } else { + return null; + } + } + + verify() { + const user = this.props.authData; + const attr = this.state.pickAttr; + if (!attr) { + this.error('Neither Email nor Phone Number selected'); + return; + } + + const that = this; + Auth.verifyCurrentUserAttribute(attr) + .then(data => { + logger.debug(data); + that.setState({ verifyAttr: attr }); + }) + .catch(err => this.error(err)); + } + + submit() { + const attr = this.state.verifyAttr; + const { code } = this.state; + Auth.verifyCurrentUserAttributeSubmit(attr, code) + .then(data => { + logger.debug(data); + this.changeState('signedIn', this.props.authData); + }) + .catch(err => this.error(err)); + } + + skip() { + this.changeState('signedIn'); + } + + // Have to do it in this way to avoid null or undefined element in React.createElement() + createPicker(unverified) { + const { email, phone_number } = unverified; + if (email && phone_number) { + return ( + this.setState({ pickAttr: value })} + > + + + + ); + } else if (email) { + return ( + this.setState({ pickAttr: value })} + > + + + ); + } else if (phone_number) { + return ( + this.setState({ pickAttr: value })} + > + + + ); + } else { + return null; + } + } + + verifyBody(theme) { + const { unverified } = this.props.authData; + if (!unverified) { + logger.debug('no unverified contact'); + return null; + } + + const { email, phone_number } = unverified; + return ( + + {this.createPicker(unverified)} + + + ); + } + + submitBody(theme) { + return ( + + this.setState({ code: text })} + label={I18n.get('Confirmation Code')} + placeholder={I18n.get('Enter your confirmation code')} + required={true} + /> + + + ); + } + + showComponent(theme) { + return ( + + +
{I18n.get('Verify Contact')}
+ {!this.state.verifyAttr && this.verifyBody(theme)} + {this.state.verifyAttr && this.submitBody(theme)} + + this.changeState('signedIn')} + > + {I18n.get('Skip')} + + + {this.state.error} +
+
+ ); + } } diff --git a/packages/aws-amplify-react-native/src/Auth/common/default-sign-up-fields.js b/packages/aws-amplify-react-native/src/Auth/common/default-sign-up-fields.js index ae16447caa7..1aa92035c22 100644 --- a/packages/aws-amplify-react-native/src/Auth/common/default-sign-up-fields.js +++ b/packages/aws-amplify-react-native/src/Auth/common/default-sign-up-fields.js @@ -1,85 +1,84 @@ - export default [ - { - label: 'Username', - key: 'username', - required: true, - placeholder: 'Username', - displayOrder: 1, - }, - { - label: 'Password', - key: 'password', - required: true, - placeholder: 'Password', - type: 'password', - displayOrder: 2, - }, - { - label: 'Email', - key: 'email', - required: true, - placeholder: 'Email', - type: 'email', - displayOrder: 3 - }, - { - label: 'Phone Number', - key: 'phone_number', - placeholder: 'Phone Number', - required: true, - displayOrder: 4 - } + { + label: 'Username', + key: 'username', + required: true, + placeholder: 'Username', + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + placeholder: 'Password', + type: 'password', + displayOrder: 2, + }, + { + label: 'Email', + key: 'email', + required: true, + placeholder: 'Email', + type: 'email', + displayOrder: 3, + }, + { + label: 'Phone Number', + key: 'phone_number', + placeholder: 'Phone Number', + required: true, + displayOrder: 4, + }, ]; export const signUpWithEmailFields = [ - { - label: 'Email', - key: 'email', - required: true, - placeholder: 'Email', - type: 'email', - displayOrder: 1 - }, - { - label: 'Password', - key: 'password', - required: true, - placeholder: 'Password', - type: 'password', - displayOrder: 2, - }, - { - label: 'Phone Number', - key: 'phone_number', - placeholder: 'Phone Number', - required: true, - displayOrder: 3 - } + { + label: 'Email', + key: 'email', + required: true, + placeholder: 'Email', + type: 'email', + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + placeholder: 'Password', + type: 'password', + displayOrder: 2, + }, + { + label: 'Phone Number', + key: 'phone_number', + placeholder: 'Phone Number', + required: true, + displayOrder: 3, + }, ]; - export const signUpWithPhoneNumberFields = [ - { - label: 'Phone Number', - key: 'phone_number', - placeholder: 'Phone Number', - required: true, - displayOrder: 1 - }, - { - label: 'Password', - key: 'password', - required: true, - placeholder: 'Password', - type: 'password', - displayOrder: 2, - }, - { - label: 'Email', - key: 'email', - required: true, - placeholder: 'Email', - type: 'email', - displayOrder: 3 - }, -]; \ No newline at end of file +export const signUpWithPhoneNumberFields = [ + { + label: 'Phone Number', + key: 'phone_number', + placeholder: 'Phone Number', + required: true, + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + placeholder: 'Password', + type: 'password', + displayOrder: 2, + }, + { + label: 'Email', + key: 'email', + required: true, + placeholder: 'Email', + type: 'email', + displayOrder: 3, + }, +]; diff --git a/packages/aws-amplify-react-native/src/Auth/index.js b/packages/aws-amplify-react-native/src/Auth/index.js index 76dcd2e14a1..c9a5de6aa62 100644 --- a/packages/aws-amplify-react-native/src/Auth/index.js +++ b/packages/aws-amplify-react-native/src/Auth/index.js @@ -30,115 +30,121 @@ import withOAuth from './withOAuth'; const logger = new Logger('auth components'); export { - Authenticator, - AuthPiece, - SignIn, - ConfirmSignIn, - SignUp, - ConfirmSignUp, - ForgotPassword, - Loading, - RequireNewPassword, - VerifyContact, - Greetings, - withOAuth + Authenticator, + AuthPiece, + SignIn, + ConfirmSignIn, + SignUp, + ConfirmSignUp, + ForgotPassword, + Loading, + RequireNewPassword, + VerifyContact, + Greetings, + withOAuth, }; export function withAuthenticator( - Comp, - includeGreetings = false, - authenticatorComponents = [], - federated = null, - theme = null, - signUpConfig = {} + Comp, + includeGreetings = false, + authenticatorComponents = [], + federated = null, + theme = null, + signUpConfig = {} ) { - class Wrapper extends React.Component { - constructor(props) { - super(props); + class Wrapper extends React.Component { + constructor(props) { + super(props); - this.handleAuthStateChange = this.handleAuthStateChange.bind(this); + this.handleAuthStateChange = this.handleAuthStateChange.bind(this); - this.state = { authState: props.authState }; + this.state = { authState: props.authState }; - this.authConfig = {}; + this.authConfig = {}; - if (typeof includeGreetings === 'object' && includeGreetings !== null){ - this.authConfig = Object.assign(this.authConfig, includeGreetings) - } else { - this.authConfig = { - includeGreetings, - authenticatorComponents, - signUpConfig - } - } - } + if (typeof includeGreetings === 'object' && includeGreetings !== null) { + this.authConfig = Object.assign(this.authConfig, includeGreetings); + } else { + this.authConfig = { + includeGreetings, + authenticatorComponents, + signUpConfig, + }; + } + } - handleAuthStateChange(state, data) { - this.setState({ authState: state, authData: data }); - if (this.props.onStateChange) { this.props.onStateChange(state, data); } - } + handleAuthStateChange(state, data) { + this.setState({ authState: state, authData: data }); + if (this.props.onStateChange) { + this.props.onStateChange(state, data); + } + } - render() { - const { authState, authData } = this.state; - const signedIn = (authState === 'signedIn'); - if (signedIn) { - if (!this.authConfig.includeGreetings) { - return ( - - ) - } + render() { + const { authState, authData } = this.state; + const signedIn = authState === 'signedIn'; + if (signedIn) { + if (!this.authConfig.includeGreetings) { + return ( + + ); + } - return ( - - - - - ) - } + return ( + + + + + ); + } - return 0} - signUpConfig={this.authConfig.signUpConfig} - onStateChange={this.handleAuthStateChange} - children={this.authConfig.authenticatorComponents} - usernameAttributes={this.authConfig.usernameAttributes} - theme={theme} - /> - } - } + return ( + 0 + } + signUpConfig={this.authConfig.signUpConfig} + onStateChange={this.handleAuthStateChange} + children={this.authConfig.authenticatorComponents} + usernameAttributes={this.authConfig.usernameAttributes} + theme={theme} + /> + ); + } + } - Object.keys(Comp).forEach(key => { - // Copy static properties in order to be as close to Comp as possible. - // One particular case is navigationOptions - try { - const excludes = [ - 'displayName', - 'childContextTypes' - ]; - if (excludes.includes(key)) { return; } + Object.keys(Comp).forEach(key => { + // Copy static properties in order to be as close to Comp as possible. + // One particular case is navigationOptions + try { + const excludes = ['displayName', 'childContextTypes']; + if (excludes.includes(key)) { + return; + } - Wrapper[key] = Comp[key]; - } catch(err) { - logger.warn('not able to assign ' + key, err); - } - }); + Wrapper[key] = Comp[key]; + } catch (err) { + logger.warn('not able to assign ' + key, err); + } + }); - return Wrapper; + return Wrapper; } diff --git a/packages/aws-amplify-react-native/src/Auth/withOAuth.js b/packages/aws-amplify-react-native/src/Auth/withOAuth.js index 37b61f5b5e8..5b6ccbd9b10 100644 --- a/packages/aws-amplify-react-native/src/Auth/withOAuth.js +++ b/packages/aws-amplify-react-native/src/Auth/withOAuth.js @@ -11,136 +11,160 @@ * and limitations under the License. */ import * as React from 'react'; -import { Linking } from "react-native"; +import { Linking } from 'react-native'; import { Logger, Hub } from '@aws-amplify/core'; -import { default as Auth, CognitoHostedUIIdentityProvider } from '@aws-amplify/auth'; +import { + default as Auth, + CognitoHostedUIIdentityProvider, +} from '@aws-amplify/auth'; const logger = new Logger('withOAuth'); -export default (Comp) => { - let listeners = []; - - return class WithOAuth extends React.Component { - constructor(props) { - super(props); - this._isMounted = false; - const config = this._getOAuthConfig(); - - const { - urlOpener = defaultUrlOpener, - } = config; - - this.urlOpener = urlOpener; - - this.hostedUISignIn = this.hostedUISignIn.bind(this); - this.signOut = this.signOut.bind(this); - this.urlOpener = this.urlOpener.bind(this); - - this.state = { - user: null, - error: null, - loading: false, - }; - - listeners.forEach(listener => Hub.remove('auth', listener)); - listeners = [this]; - this.onHubCapsule = this.onHubCapsule.bind(this); - Hub.listen('auth', this.onHubCapsule); - } - - componentDidMount() { - this._isMounted = true; - this.setState({ loading: true }, () => { - Auth.currentAuthenticatedUser().then(user => { - this.setState({ user, loading: false }) - }).catch(error => { - logger.debug(error); - this.setState({ user: null, loading: false }); - }); - }); - } - componentWillUnmount() { - this._isMounted = false; - return; - } - onHubCapsule(capsule) { - // The Auth module will emit events when user signs in, signs out, etc - if (!this._isMounted) return; - const { channel, payload } = capsule; - - if (channel === 'auth') { - switch (payload.event) { - case 'signIn': - case 'cognitoHostedUI': { - Auth.currentAuthenticatedUser().then(user => { - logger.debug('signed in'); - this.setState({ user, error: null, loading: false }); - }); - break; - } - case 'signOut': { - logger.debug('signed out'); - this.setState({ user: null, error: null, loading: false }); - break; - } - case 'signIn_failure': - case 'cognitoHostedUI_failure': { - logger.debug('not signed in'); - this.setState({ user: null, error: decodeURIComponent(payload.data), loading: false }); - break; - } - default: - break; - } - } - } - - _getOAuthConfig() { - if (!Auth || typeof Auth.configure !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - - const { oauth = undefined } = Auth.configure(); - - // to keep backward compatibility - const cognitoHostedUIConfig = oauth && (oauth.domain ? oauth : oauth.awsCognito); - const config = this.props.oauth_config || cognitoHostedUIConfig; - - return config; - } - - hostedUISignIn(provider) { - this.setState({ loading: true }, () => Auth.federatedSignIn({ provider })); - } - - signOut() { - return Auth.signOut().catch(error => logger.warn(error)); - } - - render() { - const { user: oAuthUser, error: oAuthError, loading } = this.state; - const { oauth_config: _, ...otherProps } = this.props; - - const oAuthProps = { - loading, - oAuthUser, - oAuthError, - hostedUISignIn: this.hostedUISignIn.bind(this, CognitoHostedUIIdentityProvider.Cognito), - facebookSignIn: this.hostedUISignIn.bind(this, CognitoHostedUIIdentityProvider.Facebook), - amazonSignIn: this.hostedUISignIn.bind(this, CognitoHostedUIIdentityProvider.Amazon), - googleSignIn: this.hostedUISignIn.bind(this, CognitoHostedUIIdentityProvider.Google), - customProviderSignIn: provider => this.hostedUISignIn(provider), - signOut: this.signOut, - }; - - return ; - } - } +export default Comp => { + let listeners = []; + + return class WithOAuth extends React.Component { + constructor(props) { + super(props); + this._isMounted = false; + const config = this._getOAuthConfig(); + + const { urlOpener = defaultUrlOpener } = config; + + this.urlOpener = urlOpener; + + this.hostedUISignIn = this.hostedUISignIn.bind(this); + this.signOut = this.signOut.bind(this); + this.urlOpener = this.urlOpener.bind(this); + + this.state = { + user: null, + error: null, + loading: false, + }; + + listeners.forEach(listener => Hub.remove('auth', listener)); + listeners = [this]; + this.onHubCapsule = this.onHubCapsule.bind(this); + Hub.listen('auth', this.onHubCapsule); + } + + componentDidMount() { + this._isMounted = true; + this.setState({ loading: true }, () => { + Auth.currentAuthenticatedUser() + .then(user => { + this.setState({ user, loading: false }); + }) + .catch(error => { + logger.debug(error); + this.setState({ user: null, loading: false }); + }); + }); + } + componentWillUnmount() { + this._isMounted = false; + return; + } + onHubCapsule(capsule) { + // The Auth module will emit events when user signs in, signs out, etc + if (!this._isMounted) return; + const { channel, payload } = capsule; + + if (channel === 'auth') { + switch (payload.event) { + case 'signIn': + case 'cognitoHostedUI': { + Auth.currentAuthenticatedUser().then(user => { + logger.debug('signed in'); + this.setState({ user, error: null, loading: false }); + }); + break; + } + case 'signOut': { + logger.debug('signed out'); + this.setState({ user: null, error: null, loading: false }); + break; + } + case 'signIn_failure': + case 'cognitoHostedUI_failure': { + logger.debug('not signed in'); + this.setState({ + user: null, + error: decodeURIComponent(payload.data), + loading: false, + }); + break; + } + default: + break; + } + } + } + + _getOAuthConfig() { + if (!Auth || typeof Auth.configure !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + + const { oauth = undefined } = Auth.configure(); + + // to keep backward compatibility + const cognitoHostedUIConfig = + oauth && (oauth.domain ? oauth : oauth.awsCognito); + const config = this.props.oauth_config || cognitoHostedUIConfig; + + return config; + } + + hostedUISignIn(provider) { + this.setState({ loading: true }, () => + Auth.federatedSignIn({ provider }) + ); + } + + signOut() { + return Auth.signOut().catch(error => logger.warn(error)); + } + + render() { + const { user: oAuthUser, error: oAuthError, loading } = this.state; + const { oauth_config: _, ...otherProps } = this.props; + + const oAuthProps = { + loading, + oAuthUser, + oAuthError, + hostedUISignIn: this.hostedUISignIn.bind( + this, + CognitoHostedUIIdentityProvider.Cognito + ), + facebookSignIn: this.hostedUISignIn.bind( + this, + CognitoHostedUIIdentityProvider.Facebook + ), + amazonSignIn: this.hostedUISignIn.bind( + this, + CognitoHostedUIIdentityProvider.Amazon + ), + googleSignIn: this.hostedUISignIn.bind( + this, + CognitoHostedUIIdentityProvider.Google + ), + customProviderSignIn: provider => this.hostedUISignIn(provider), + signOut: this.signOut, + }; + + return ; + } + }; }; const defaultUrlOpener = (url, redirectUrl) => { - logger.debug(`opening url: ${url}, redirectUrl: ${redirectUrl}`); + logger.debug(`opening url: ${url}, redirectUrl: ${redirectUrl}`); - return Linking.openURL(url); -} + return Linking.openURL(url); +}; diff --git a/packages/aws-amplify-react-native/src/CountryDialCodes.js b/packages/aws-amplify-react-native/src/CountryDialCodes.js index dc7f048043f..33e0c116d19 100644 --- a/packages/aws-amplify-react-native/src/CountryDialCodes.js +++ b/packages/aws-amplify-react-native/src/CountryDialCodes.js @@ -1,208 +1,208 @@ export default [ - "+1", - "+7", - "+20", - "+27", - "+30", - "+31", - "+32", - "+33", - "+34", - "+36", - "+39", - "+40", - "+41", - "+43", - "+44", - "+45", - "+46", - "+47", - "+48", - "+49", - "+51", - "+52", - "+53", - "+54", - "+55", - "+56", - "+57", - "+58", - "+60", - "+61", - "+62", - "+63", - "+64", - "+65", - "+66", - "+81", - "+82", - "+84", - "+86", - "+90", - "+91", - "+92", - "+93", - "+94", - "+95", - "+98", - "+212", - "+213", - "+216", - "+218", - "+220", - "+221", - "+222", - "+223", - "+224", - "+225", - "+226", - "+227", - "+228", - "+229", - "+230", - "+231", - "+232", - "+233", - "+234", - "+235", - "+236", - "+237", - "+238", - "+239", - "+240", - "+241", - "+242", - "+243", - "+244", - "+245", - "+246", - "+248", - "+249", - "+250", - "+251", - "+252", - "+253", - "+254", - "+255", - "+256", - "+257", - "+258", - "+260", - "+261", - "+262", - "+263", - "+264", - "+265", - "+266", - "+267", - "+268", - "+269", - "+290", - "+291", - "+297", - "+298", - "+299", - "+345", - "+350", - "+351", - "+352", - "+353", - "+354", - "+355", - "+356", - "+357", - "+358", - "+359", - "+370", - "+371", - "+372", - "+373", - "+374", - "+375", - "+376", - "+377", - "+378", - "+379", - "+380", - "+381", - "+382", - "+385", - "+386", - "+387", - "+389", - "+420", - "+421", - "+423", - "+500", - "+501", - "+502", - "+503", - "+504", - "+505", - "+506", - "+507", - "+508", - "+509", - "+537", - "+590", - "+591", - "+593", - "+594", - "+595", - "+596", - "+597", - "+598", - "+599", - "+670", - "+672", - "+673", - "+674", - "+675", - "+676", - "+677", - "+678", - "+679", - "+680", - "+681", - "+682", - "+683", - "+685", - "+686", - "+687", - "+688", - "+689", - "+690", - "+691", - "+692", - "+850", - "+852", - "+853", - "+855", - "+856", - "+872", - "+880", - "+886", - "+960", - "+961", - "+962", - "+963", - "+964", - "+965", - "+966", - "+967", - "+968", - "+970", - "+971", - "+972", - "+973", - "+974", - "+975", - "+976", - "+977", - "+992", - "+993", - "+994", - "+995", - "+996", - "+998", + '+1', + '+7', + '+20', + '+27', + '+30', + '+31', + '+32', + '+33', + '+34', + '+36', + '+39', + '+40', + '+41', + '+43', + '+44', + '+45', + '+46', + '+47', + '+48', + '+49', + '+51', + '+52', + '+53', + '+54', + '+55', + '+56', + '+57', + '+58', + '+60', + '+61', + '+62', + '+63', + '+64', + '+65', + '+66', + '+81', + '+82', + '+84', + '+86', + '+90', + '+91', + '+92', + '+93', + '+94', + '+95', + '+98', + '+212', + '+213', + '+216', + '+218', + '+220', + '+221', + '+222', + '+223', + '+224', + '+225', + '+226', + '+227', + '+228', + '+229', + '+230', + '+231', + '+232', + '+233', + '+234', + '+235', + '+236', + '+237', + '+238', + '+239', + '+240', + '+241', + '+242', + '+243', + '+244', + '+245', + '+246', + '+248', + '+249', + '+250', + '+251', + '+252', + '+253', + '+254', + '+255', + '+256', + '+257', + '+258', + '+260', + '+261', + '+262', + '+263', + '+264', + '+265', + '+266', + '+267', + '+268', + '+269', + '+290', + '+291', + '+297', + '+298', + '+299', + '+345', + '+350', + '+351', + '+352', + '+353', + '+354', + '+355', + '+356', + '+357', + '+358', + '+359', + '+370', + '+371', + '+372', + '+373', + '+374', + '+375', + '+376', + '+377', + '+378', + '+379', + '+380', + '+381', + '+382', + '+385', + '+386', + '+387', + '+389', + '+420', + '+421', + '+423', + '+500', + '+501', + '+502', + '+503', + '+504', + '+505', + '+506', + '+507', + '+508', + '+509', + '+537', + '+590', + '+591', + '+593', + '+594', + '+595', + '+596', + '+597', + '+598', + '+599', + '+670', + '+672', + '+673', + '+674', + '+675', + '+676', + '+677', + '+678', + '+679', + '+680', + '+681', + '+682', + '+683', + '+685', + '+686', + '+687', + '+688', + '+689', + '+690', + '+691', + '+692', + '+850', + '+852', + '+853', + '+855', + '+856', + '+872', + '+880', + '+886', + '+960', + '+961', + '+962', + '+963', + '+964', + '+965', + '+966', + '+967', + '+968', + '+970', + '+971', + '+972', + '+973', + '+974', + '+975', + '+976', + '+977', + '+992', + '+993', + '+994', + '+995', + '+996', + '+998', ]; diff --git a/packages/aws-amplify-react-native/src/Interactions/ChatBot.js b/packages/aws-amplify-react-native/src/Interactions/ChatBot.js index af4c1afcf33..fe5fd0490f0 100644 --- a/packages/aws-amplify-react-native/src/Interactions/ChatBot.js +++ b/packages/aws-amplify-react-native/src/Interactions/ChatBot.js @@ -1,8 +1,14 @@ -import React, { Component } from "react"; -import { View, TextInput, Text, KeyboardAvoidingView, ScrollView } from "react-native"; +import React, { Component } from 'react'; +import { + View, + TextInput, + Text, + KeyboardAvoidingView, + ScrollView, +} from 'react-native'; import Interactions from '@aws-amplify/interactions'; -import { I18n } from "aws-amplify"; -import { AmplifyButton } from "../AmplifyUI"; +import { I18n } from 'aws-amplify'; +import { AmplifyButton } from '../AmplifyUI'; import { ConsoleLogger as Logger } from '@aws-amplify/core'; var Voice; @@ -14,467 +20,518 @@ var Buffer = require('buffer/').Buffer; const logger = new Logger('ChatBot'); const styles = { - container: { - flex: 1, - flexDirection: 'column', - backgroundColor: '#fff', - alignItems: 'center', - alignSelf: 'stretch', - justifyContent: 'center', - }, - list: { - flex: 1, - flexDirection: 'column', - alignSelf: 'stretch', - padding: 5, - }, - itemMe: { - textAlign: 'right', - alignSelf: 'flex-end', - padding: 8, - margin: 8, - backgroundColor: '#CCCCCC', - borderRadius: 15, - overflow: 'hidden', - }, - itemBot: { - textAlign: 'left', - alignSelf: 'flex-start', - padding: 8, - margin: 8, - color: 'white', - backgroundColor: '#0099FF', - borderRadius: 15, - overflow: 'hidden', - }, - inputContainer: { - flexDirection: 'row', - }, - textInput: { - flex: 1, - }, - buttonMic: { - backgroundColor: "#ffc266" - } + container: { + flex: 1, + flexDirection: 'column', + backgroundColor: '#fff', + alignItems: 'center', + alignSelf: 'stretch', + justifyContent: 'center', + }, + list: { + flex: 1, + flexDirection: 'column', + alignSelf: 'stretch', + padding: 5, + }, + itemMe: { + textAlign: 'right', + alignSelf: 'flex-end', + padding: 8, + margin: 8, + backgroundColor: '#CCCCCC', + borderRadius: 15, + overflow: 'hidden', + }, + itemBot: { + textAlign: 'left', + alignSelf: 'flex-start', + padding: 8, + margin: 8, + color: 'white', + backgroundColor: '#0099FF', + borderRadius: 15, + overflow: 'hidden', + }, + inputContainer: { + flexDirection: 'row', + }, + textInput: { + flex: 1, + }, + buttonMic: { + backgroundColor: '#ffc266', + }, }; const STATES = { - INITIAL: 'INITIAL', - LISTENING: 'LISTENING', - SENDING: 'SENDING', - SPEAKING: 'SPEAKING' + INITIAL: 'INITIAL', + LISTENING: 'LISTENING', + SENDING: 'SENDING', + SPEAKING: 'SPEAKING', }; const MIC_BUTTON_TEXT = { - PASSIVE: '🎤', - RECORDING: '🔴' -} + PASSIVE: '🎤', + RECORDING: '🔴', +}; let timer = null; export class ChatBot extends Component { - constructor(props) { - super(props); - this.state = { - dialog: [{ - message: this.props.welcomeMessage || 'Welcome to Lex', - from: 'system' - }], - inputText: '', - inputEditable: true, - micText: MIC_BUTTON_TEXT.PASSIVE, - voice: false, - conversationOngoing: false - }; - this.listItems = this.listItems.bind(this); - this.submit = this.submit.bind(this); - this.listItemsRef = React.createRef(); - this.reset = this.reset.bind(this); - - this.startRecognizing = this.startRecognizing.bind(this); - this.handleMicButton = this.handleMicButton.bind(this); - - if (this.props.voiceEnabled) { - if (!this.props.voiceLibs) { - throw new Error('Missing voiceLibs for voice interactions') - } - Voice = this.props.voiceLibs.Voice; - Sound = this.props.voiceLibs.Sound; - RNFS = this.props.voiceLibs.RNFS; - - if (!Voice || typeof Voice.start !== 'function' || - typeof Voice.stop !== 'function' || - typeof Voice.isRecognizing !== 'function') { - throw new Error('Missing react-native-voice') - } - if (!Sound) { - throw new Error('Missing react-native-sound') - } - if (!RNFS || typeof RNFS.exists !== 'function' || - typeof RNFS.unlink !== 'function' || - typeof RNFS.writeFile !== 'function') { - throw new Error('Missing react-native-fs') - } - - Voice.onSpeechStart = this.onSpeechStart.bind(this); - Voice.onSpeechEnd = this.onSpeechEnd.bind(this); - Voice.onSpeechError = this.onSpeechError.bind(this); - Voice.onSpeechResults = this.onSpeechResults.bind(this); - } - - } - - listItems() { - const { styles: overrideStyles } = this.props; - - return this.state.dialog.map((m, i) => { - if (m.from === 'me') { return {m.message} } - else if (m.from === 'system') { return {m.message} } - else { return {m.message} } - }); - }; - - async submit(voiceResponse) { - if (!this.state.inputText) { - return; - } - - await new Promise(resolve => this.setState({ - dialog: [ - ...this.state.dialog, - { message: this.state.inputText, from: 'me' }, - ] - }, resolve)); - - let response; - if (voiceResponse === true) { - const interactionsMessage = { - content: this.state.inputText, - options: { - messageType: 'text' - } - }; - response = await Interactions.send(this.props.botName, interactionsMessage); - } else { - response = await Interactions.send(this.props.botName, this.state.inputText); - } - - this.setState({ - dialog: [ - ...this.state.dialog, - response && response.message && { from: 'bot', message: response.message } - ].filter(Boolean), - inputText: '', - inputEditable: true, - micText: MIC_BUTTON_TEXT.PASSIVE, - }, () => { - setTimeout(() => { - this.listItemsRef.current.scrollToEnd(); - }, 50); - }); - - if (this.state.voice) { - this.setState({ - voice: false - }) - - const path = `${RNFS.DocumentDirectoryPath}/responseAudio.mp3`; - const data = Buffer.from(response.audioStream).toString('base64'); - await RNFS.writeFile(path, data, 'base64'); - const speech = new Sound(path, '', async(err) => { - if (!err) { - speech.play(async () => { - speech.release(); - RNFS.exists(path).then((res) => { - if (res) { - RNFS.unlink(path) - } - }) - if (response.dialogState === 'ElicitSlot' && this.props.conversationModeOn) { - await this.startRecognizing(); - } - }); - } else { - logger.error(err) - } - }); - } - } - - getOnComplete(fn) { - return (...args) => { - const { clearOnComplete } = this.props; - const message = fn(...args); - - this.setState({ - dialog: [ - ...(!clearOnComplete && this.state.dialog), - message && { from: 'bot', message } - ].filter(Boolean), - }, () => { - setTimeout(() => { - this.listItemsRef.current.scrollToEnd(); - }, 50); - }); - } - } - - componentDidMount() { - const { onComplete, botName } = this.props; - - if (onComplete && botName) { - Interactions.onComplete(botName, this.getOnComplete(onComplete, this)); - } - } - - componentDidUpdate(prevProps) { - const { onComplete, botName } = this.props; - - if ((botName !== prevProps.botName) || (onComplete !== prevProps.onComplete)) { - Interactions.onComplete(botName, this.getOnComplete(onComplete, this)); - } - } - - onSpeechStart(e) { - this.setState({ - currentConversationState: STATES.LISTENING - }); - }; - - async onSpeechEnd(e) { - timer = null; - - this.setState({ - currentConversationState: STATES.SENDING - }); - await this.submit(true); - - }; - - onSpeechError(e) { - logger.error(e) - this.setState({ - error: JSON.stringify(e.error), - }); - }; - - onSpeechResults(e) { - this.setState({ - inputText: e.value.join(" ") - }); - if (timer !== null) { - clearTimeout(timer); - } - timer = setTimeout( async () => { - await Voice.stop(); - }, this.state.silenceDelay) - }; - - async startRecognizing() { - this.setState({ - inputText: 'Speak into the mic...', - inputEditable: false, - micText: MIC_BUTTON_TEXT.RECORDING, - voice: true, - }); - - if (this.props.conversationModeOn) { - this.setState({ - conversationOngoing: true, - }) - } - - try { - await Voice.start('en-US'); - } catch (e) { - logger.error(e); - } - - }; - - async handleMicButton() { - if (this.state.conversationOngoing || await Voice.isRecognizing()) { - await this.reset(); - } else { - await this.startRecognizing(); - } - } - - async reset() { - this.setState({ - inputText: '', - inputEditable: true, - micText: MIC_BUTTON_TEXT.PASSIVE, - voice: false, - conversationOngoing: false, - }) - await Voice.stop() - - } - - render() { - const { styles: overrideStyles } = this.props; - - return ( - - - {this.listItems()} - - this.setState({ inputText })} - inputText={this.state.inputText} - onSubmitEditing={this.submit} - editable={this.state.inputEditable} - handleMicButton={this.handleMicButton} - submit={this.submit}> - - - ); - } + constructor(props) { + super(props); + this.state = { + dialog: [ + { + message: this.props.welcomeMessage || 'Welcome to Lex', + from: 'system', + }, + ], + inputText: '', + inputEditable: true, + micText: MIC_BUTTON_TEXT.PASSIVE, + voice: false, + conversationOngoing: false, + }; + this.listItems = this.listItems.bind(this); + this.submit = this.submit.bind(this); + this.listItemsRef = React.createRef(); + this.reset = this.reset.bind(this); + + this.startRecognizing = this.startRecognizing.bind(this); + this.handleMicButton = this.handleMicButton.bind(this); + + if (this.props.voiceEnabled) { + if (!this.props.voiceLibs) { + throw new Error('Missing voiceLibs for voice interactions'); + } + Voice = this.props.voiceLibs.Voice; + Sound = this.props.voiceLibs.Sound; + RNFS = this.props.voiceLibs.RNFS; + + if ( + !Voice || + typeof Voice.start !== 'function' || + typeof Voice.stop !== 'function' || + typeof Voice.isRecognizing !== 'function' + ) { + throw new Error('Missing react-native-voice'); + } + if (!Sound) { + throw new Error('Missing react-native-sound'); + } + if ( + !RNFS || + typeof RNFS.exists !== 'function' || + typeof RNFS.unlink !== 'function' || + typeof RNFS.writeFile !== 'function' + ) { + throw new Error('Missing react-native-fs'); + } + + Voice.onSpeechStart = this.onSpeechStart.bind(this); + Voice.onSpeechEnd = this.onSpeechEnd.bind(this); + Voice.onSpeechError = this.onSpeechError.bind(this); + Voice.onSpeechResults = this.onSpeechResults.bind(this); + } + } + + listItems() { + const { styles: overrideStyles } = this.props; + + return this.state.dialog.map((m, i) => { + if (m.from === 'me') { + return ( + + {m.message} + + ); + } else if (m.from === 'system') { + return ( + + {m.message} + + ); + } else { + return ( + + {m.message} + + ); + } + }); + } + + async submit(voiceResponse) { + if (!this.state.inputText) { + return; + } + + await new Promise(resolve => + this.setState( + { + dialog: [ + ...this.state.dialog, + { message: this.state.inputText, from: 'me' }, + ], + }, + resolve + ) + ); + + let response; + if (voiceResponse === true) { + const interactionsMessage = { + content: this.state.inputText, + options: { + messageType: 'text', + }, + }; + response = await Interactions.send( + this.props.botName, + interactionsMessage + ); + } else { + response = await Interactions.send( + this.props.botName, + this.state.inputText + ); + } + + this.setState( + { + dialog: [ + ...this.state.dialog, + response && + response.message && { from: 'bot', message: response.message }, + ].filter(Boolean), + inputText: '', + inputEditable: true, + micText: MIC_BUTTON_TEXT.PASSIVE, + }, + () => { + setTimeout(() => { + this.listItemsRef.current.scrollToEnd(); + }, 50); + } + ); + + if (this.state.voice) { + this.setState({ + voice: false, + }); + + const path = `${RNFS.DocumentDirectoryPath}/responseAudio.mp3`; + const data = Buffer.from(response.audioStream).toString('base64'); + await RNFS.writeFile(path, data, 'base64'); + const speech = new Sound(path, '', async err => { + if (!err) { + speech.play(async () => { + speech.release(); + RNFS.exists(path).then(res => { + if (res) { + RNFS.unlink(path); + } + }); + if ( + response.dialogState === 'ElicitSlot' && + this.props.conversationModeOn + ) { + await this.startRecognizing(); + } + }); + } else { + logger.error(err); + } + }); + } + } + + getOnComplete(fn) { + return (...args) => { + const { clearOnComplete } = this.props; + const message = fn(...args); + + this.setState( + { + dialog: [ + ...(!clearOnComplete && this.state.dialog), + message && { from: 'bot', message }, + ].filter(Boolean), + }, + () => { + setTimeout(() => { + this.listItemsRef.current.scrollToEnd(); + }, 50); + } + ); + }; + } + + componentDidMount() { + const { onComplete, botName } = this.props; + + if (onComplete && botName) { + Interactions.onComplete(botName, this.getOnComplete(onComplete, this)); + } + } + + componentDidUpdate(prevProps) { + const { onComplete, botName } = this.props; + + if (botName !== prevProps.botName || onComplete !== prevProps.onComplete) { + Interactions.onComplete(botName, this.getOnComplete(onComplete, this)); + } + } + + onSpeechStart(e) { + this.setState({ + currentConversationState: STATES.LISTENING, + }); + } + + async onSpeechEnd(e) { + timer = null; + + this.setState({ + currentConversationState: STATES.SENDING, + }); + await this.submit(true); + } + + onSpeechError(e) { + logger.error(e); + this.setState({ + error: JSON.stringify(e.error), + }); + } + + onSpeechResults(e) { + this.setState({ + inputText: e.value.join(' '), + }); + if (timer !== null) { + clearTimeout(timer); + } + timer = setTimeout(async () => { + await Voice.stop(); + }, this.state.silenceDelay); + } + + async startRecognizing() { + this.setState({ + inputText: 'Speak into the mic...', + inputEditable: false, + micText: MIC_BUTTON_TEXT.RECORDING, + voice: true, + }); + + if (this.props.conversationModeOn) { + this.setState({ + conversationOngoing: true, + }); + } + + try { + await Voice.start('en-US'); + } catch (e) { + logger.error(e); + } + } + + async handleMicButton() { + if (this.state.conversationOngoing || (await Voice.isRecognizing())) { + await this.reset(); + } else { + await this.startRecognizing(); + } + } + + async reset() { + this.setState({ + inputText: '', + inputEditable: true, + micText: MIC_BUTTON_TEXT.PASSIVE, + voice: false, + conversationOngoing: false, + }); + await Voice.stop(); + } + + render() { + const { styles: overrideStyles } = this.props; + + return ( + + + {this.listItems()} + + this.setState({ inputText })} + inputText={this.state.inputText} + onSubmitEditing={this.submit} + editable={this.state.inputEditable} + handleMicButton={this.handleMicButton} + submit={this.submit} + > + + ); + } } function ChatBotInputs(props) { - const voiceEnabled = props.voiceEnabled; - const textEnabled = props.textEnabled; - const styles = props.styles; - const overrideStyles = props.overrideStyles; - const onChangeText = props.onChangeText; - const inputText = props.inputText; - const onSubmitEditing = props.onSubmitEditing; - let editable = props.editable; - const handleMicButton = props.handleMicButton; - const micText = props.micText; - const submit = props.submit; - - if (voiceEnabled && textEnabled) { - placeholder = 'Type your message or tap 🎤' - } - - if (voiceEnabled && !textEnabled) { - placeholder = 'Tap the mic button' - editable = false; - } - - if (!voiceEnabled && textEnabled) { - placeholder = 'Type your message here' - } - - if (!voiceEnabled && !textEnabled) { - return( - No Chatbot inputs enabled. Set at least one of voiceEnabled or textEnabled in the props. - ) - } - - return( - - - - - - ) + const voiceEnabled = props.voiceEnabled; + const textEnabled = props.textEnabled; + const styles = props.styles; + const overrideStyles = props.overrideStyles; + const onChangeText = props.onChangeText; + const inputText = props.inputText; + const onSubmitEditing = props.onSubmitEditing; + let editable = props.editable; + const handleMicButton = props.handleMicButton; + const micText = props.micText; + const submit = props.submit; + + if (voiceEnabled && textEnabled) { + placeholder = 'Type your message or tap 🎤'; + } + + if (voiceEnabled && !textEnabled) { + placeholder = 'Tap the mic button'; + editable = false; + } + + if (!voiceEnabled && textEnabled) { + placeholder = 'Type your message here'; + } + + if (!voiceEnabled && !textEnabled) { + return ( + + No Chatbot inputs enabled. Set at least one of voiceEnabled or + textEnabled in the props.{' '} + + ); + } + + return ( + + + + + + ); } function ChatBotTextInput(props) { - const styles = props.styles; - const overrideStyles = props.overrideStyles; - const onChangeText = props.onChangeText; - const inputText = props.inputText; - const onSubmitEditing = props.onSubmitEditing; - const editable = props.editable; - const placeholder = props.placeholder; - - return( - - - ) + const styles = props.styles; + const overrideStyles = props.overrideStyles; + const onChangeText = props.onChangeText; + const inputText = props.inputText; + const onSubmitEditing = props.onSubmitEditing; + const editable = props.editable; + const placeholder = props.placeholder; + + return ( + + ); } function ChatBotTextButton(props) { - const textEnabled = props.textEnabled; - const styles = props.styles; - const overrideStyles = props.overrideStyles; - const submit = props.submit; - - if (!textEnabled) { - return null; - } - - return( - - ) + const textEnabled = props.textEnabled; + const styles = props.styles; + const overrideStyles = props.overrideStyles; + const submit = props.submit; + + if (!textEnabled) { + return null; + } + + return ( + + ); } function ChatBotMicButton(props) { - const voiceEnabled = props.voiceEnabled; - const styles = props.styles; - const overrideStyles = props.overrideStyles; - const handleMicButton = props.handleMicButton; - const micText = props.micText; - - if (!voiceEnabled) { - return null; - } - - return( - - ) + const voiceEnabled = props.voiceEnabled; + const styles = props.styles; + const overrideStyles = props.overrideStyles; + const handleMicButton = props.handleMicButton; + const micText = props.micText; + + if (!voiceEnabled) { + return null; + } + + return ( + + ); } ChatBot.defaultProps = { - botName: undefined, - onComplete: undefined, - clearOnComplete: false, - styles: {}, - silenceDelay: 1000, - conversationModeOn: false, - voiceEnabled: false, - textEnabled: true + botName: undefined, + onComplete: undefined, + clearOnComplete: false, + styles: {}, + silenceDelay: 1000, + conversationModeOn: false, + voiceEnabled: false, + textEnabled: true, }; -export default ChatBot; \ No newline at end of file +export default ChatBot; diff --git a/packages/aws-amplify-react-native/src/Interactions/ReactNativeModules/index.js b/packages/aws-amplify-react-native/src/Interactions/ReactNativeModules/index.js index 15a86891ee0..72fda5e77db 100644 --- a/packages/aws-amplify-react-native/src/Interactions/ReactNativeModules/index.js +++ b/packages/aws-amplify-react-native/src/Interactions/ReactNativeModules/index.js @@ -1,11 +1,11 @@ -import Voice from 'react-native-voice' -import Sound from 'react-native-sound' -import RNFS from 'react-native-fs' +import Voice from 'react-native-voice'; +import Sound from 'react-native-sound'; +import RNFS from 'react-native-fs'; const VoiceExports = { - Voice, - Sound, - RNFS -} + Voice, + Sound, + RNFS, +}; -export default VoiceExports \ No newline at end of file +export default VoiceExports; diff --git a/packages/aws-amplify-react-native/src/Storage/S3Album.js b/packages/aws-amplify-react-native/src/Storage/S3Album.js index b333af60fd2..4143a6b8ad7 100644 --- a/packages/aws-amplify-react-native/src/Storage/S3Album.js +++ b/packages/aws-amplify-react-native/src/Storage/S3Album.js @@ -12,63 +12,61 @@ */ import React, { Component } from 'react'; -import { - ScrollView, - Dimensions, - StyleSheet -} from 'react-native'; -import { - Storage, - Logger -} from 'aws-amplify'; +import { ScrollView, Dimensions, StyleSheet } from 'react-native'; +import { Storage, Logger } from 'aws-amplify'; import AmplifyTheme from '../AmplifyTheme'; import S3Image from './S3Image'; const logger = new Logger('Storage.S3Album'); export default class S3Album extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.state = { images: [] }; - } + this.state = { images: [] }; + } - componentDidMount() { - const { path, level, filter } = this.props; - logger.debug(path); - Storage.list(path, { level: level? level : 'public' }) - .then(data => { - logger.debug(data); - if (filter) { data = filter(data); } - this.setState({ images: data }); - }) - .catch(err => logger.warn(err)); - } + componentDidMount() { + const { path, level, filter } = this.props; + logger.debug(path); + Storage.list(path, { level: level ? level : 'public' }) + .then(data => { + logger.debug(data); + if (filter) { + data = filter(data); + } + this.setState({ images: data }); + }) + .catch(err => logger.warn(err)); + } - render() { - const { images } = this.state; - if (!images) { return null; } + render() { + const { images } = this.state; + if (!images) { + return null; + } - const { width, height } = Dimensions.get('window'); - const theme = this.props.theme || AmplifyTheme; - const albumStyle = Object.assign( - {}, - StyleSheet.flatten(theme.album), - { width: '100%', height: height } - ); - const list = this.state.images.map(image => { - return - }); - return ( - - {list} - - ) - } + const { width, height } = Dimensions.get('window'); + const theme = this.props.theme || AmplifyTheme; + const albumStyle = Object.assign({}, StyleSheet.flatten(theme.album), { + width: '100%', + height: height, + }); + const list = this.state.images.map(image => { + return ( + + ); + }); + return ( + + {list} + + ); + } } diff --git a/packages/aws-amplify-react-native/src/Storage/S3Image.js b/packages/aws-amplify-react-native/src/Storage/S3Image.js index bb5240e2954..f1fb05ea8b8 100644 --- a/packages/aws-amplify-react-native/src/Storage/S3Image.js +++ b/packages/aws-amplify-react-native/src/Storage/S3Image.js @@ -12,81 +12,85 @@ */ import React, { Component } from 'react'; -import { - Image, - StyleSheet -} from 'react-native'; -import { - Storage, - Logger -} from 'aws-amplify'; +import { Image, StyleSheet } from 'react-native'; +import { Storage, Logger } from 'aws-amplify'; import AmplifyTheme from '../AmplifyTheme'; const logger = new Logger('Storage.S3Image'); export default class S3Image extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.state = { src: null }; - } + this.state = { src: null }; + } - getImageSource() { - const { imgKey, level } = this.props; - Storage.get(imgKey, { level : level? level : 'public'}) - .then(url => { - logger.debug(url); - this.setState({ - src: { uri: url } - }); - }) - .catch(err => logger.warn(err)); - } + getImageSource() { + const { imgKey, level } = this.props; + Storage.get(imgKey, { level: level ? level : 'public' }) + .then(url => { + logger.debug(url); + this.setState({ + src: { uri: url }, + }); + }) + .catch(err => logger.warn(err)); + } - load() { - const { imgKey, body, contentType, level } = this.props; - if (!imgKey) { - logger.debug('empty imgKey'); - return ; - } + load() { + const { imgKey, body, contentType, level } = this.props; + if (!imgKey) { + logger.debug('empty imgKey'); + return; + } - const that = this; - logger.debug('loading ' + imgKey + '...'); - if (body) { - const type = contentType? contentType : 'binary/octet-stream'; - const opt = { - contentType: type, - level: level? level : 'public' - } - const ret = Storage.put(imgKey, body, opt); - ret.then(data => { - logger.debug(data); - that.getImageSource(); - }) - .catch(err => logger.warn(err)); - } else { - that.getImageSource(); - } - } + const that = this; + logger.debug('loading ' + imgKey + '...'); + if (body) { + const type = contentType ? contentType : 'binary/octet-stream'; + const opt = { + contentType: type, + level: level ? level : 'public', + }; + const ret = Storage.put(imgKey, body, opt); + ret + .then(data => { + logger.debug(data); + that.getImageSource(); + }) + .catch(err => logger.warn(err)); + } else { + that.getImageSource(); + } + } - componentDidMount() { - this.load(); - } + componentDidMount() { + this.load(); + } - componentDidUpdate(prevProps) { - if (prevProps.imgKey !== this.props.imgKey || prevProps.body !== this.props.body) { - this.load(); - } - } + componentDidUpdate(prevProps) { + if ( + prevProps.imgKey !== this.props.imgKey || + prevProps.body !== this.props.body + ) { + this.load(); + } + } - render() { - const { src } = this.state; - if (!src) { return null; } + render() { + const { src } = this.state; + if (!src) { + return null; + } - const { style, resizeMode} = this.props; - const theme = this.props.theme || AmplifyTheme; - const photoStyle = Object.assign({}, StyleSheet.flatten(theme.photo), style); + const { style, resizeMode } = this.props; + const theme = this.props.theme || AmplifyTheme; + const photoStyle = Object.assign( + {}, + StyleSheet.flatten(theme.photo), + style + ); - return - } + return ; + } } diff --git a/packages/aws-amplify-react-native/src/index.js b/packages/aws-amplify-react-native/src/index.js index 8f4e75bf4f4..a5f08628964 100644 --- a/packages/aws-amplify-react-native/src/index.js +++ b/packages/aws-amplify-react-native/src/index.js @@ -14,7 +14,6 @@ import { default as AmplifyCore, I18n } from 'aws-amplify'; import dict from './AmplifyI18n'; - export { default as AmplifyTheme } from './AmplifyTheme'; export { MapEntries as AmplifyMessageMapEntries } from './AmplifyMessageMap'; export * from './AmplifyUI'; @@ -24,25 +23,25 @@ export * from './Storage'; export * from './Interactions'; const configure = function(config) { - const msg = [ - '', - '\x1b[33mWarning: Amplify.configure() is deprecated from aws-amplify-react-native.', - ' Please import aws-amplify package to configure AWS Amplify\x1b[0m', - '', - ' Example:', - '', - ' \x1b[36mimport Amplify from \'aws-amplify\';', - ' import aws_exports from \'./aws-exports\';', - '', - ' Amplify.configure(aws_exports)\x1b[0m', - '' - ].join('\n'); - console.log(msg); - AmplifyCore.configure(config); + const msg = [ + '', + '\x1b[33mWarning: Amplify.configure() is deprecated from aws-amplify-react-native.', + ' Please import aws-amplify package to configure AWS Amplify\x1b[0m', + '', + ' Example:', + '', + " \x1b[36mimport Amplify from 'aws-amplify';", + " import aws_exports from './aws-exports';", + '', + ' Amplify.configure(aws_exports)\x1b[0m', + '', + ].join('\n'); + console.log(msg); + AmplifyCore.configure(config); }; const Amplify = { - configure: configure + configure: configure, }; export default Amplify; diff --git a/packages/aws-amplify-react/CHANGELOG.md b/packages/aws-amplify-react/CHANGELOG.md index d897e29f962..f515b504850 100644 --- a/packages/aws-amplify-react/CHANGELOG.md +++ b/packages/aws-amplify-react/CHANGELOG.md @@ -7,2237 +7,1680 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package aws-amplify-react - - - - ## [2.4.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.13...aws-amplify-react@2.4.2) (2019-09-05) **Note:** Version bump only for package aws-amplify-react - - - - ## [2.3.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.12...aws-amplify-react@2.3.13) (2019-09-04) **Note:** Version bump only for package aws-amplify-react - - - - ## [2.3.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.11...aws-amplify-react@2.3.12) (2019-07-30) **Note:** Version bump only for package aws-amplify-react - - - - ## [2.3.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.10...aws-amplify-react@2.3.11) (2019-07-18) **Note:** Version bump only for package aws-amplify-react - - - - -## [2.3.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.10-unstable.2...aws-amplify-react@2.3.10) (2019-07-09) - - +## [2.3.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.10-unstable.2...aws-amplify-react@2.3.10) (2019-07-09) **Note:** Version bump only for package aws-amplify-react -## [2.3.10-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.10-unstable.1...aws-amplify-react@2.3.10-unstable.2) (2019-07-09) - - +## [2.3.10-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.10-unstable.1...aws-amplify-react@2.3.10-unstable.2) (2019-07-09) **Note:** Version bump only for package aws-amplify-react -## [2.3.10-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.10-unstable.0...aws-amplify-react@2.3.10-unstable.1) (2019-07-03) +## [2.3.10-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.10-unstable.0...aws-amplify-react@2.3.10-unstable.1) (2019-07-03) ### Bug Fixes -* **aws-amplify-react:** image will reload when level is changed ([0b39eb6](https://github.com/aws/aws-amplify/commit/0b39eb6)) - - - +- **aws-amplify-react:** image will reload when level is changed ([0b39eb6](https://github.com/aws/aws-amplify/commit/0b39eb6)) -## [2.3.10-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.9...aws-amplify-react@2.3.10-unstable.0) (2019-06-27) - - +## [2.3.10-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.9...aws-amplify-react@2.3.10-unstable.0) (2019-06-27) **Note:** Version bump only for package aws-amplify-react -## [2.3.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.9-unstable.3...aws-amplify-react@2.3.9) (2019-06-17) - - +## [2.3.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.9-unstable.3...aws-amplify-react@2.3.9) (2019-06-17) **Note:** Version bump only for package aws-amplify-react -## [2.3.9-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.9-unstable.2...aws-amplify-react@2.3.9-unstable.3) (2019-06-07) - - +## [2.3.9-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.9-unstable.2...aws-amplify-react@2.3.9-unstable.3) (2019-06-07) **Note:** Version bump only for package aws-amplify-react -## [2.3.9-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.9-unstable.1...aws-amplify-react@2.3.9-unstable.2) (2019-06-06) - - +## [2.3.9-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.9-unstable.1...aws-amplify-react@2.3.9-unstable.2) (2019-06-06) **Note:** Version bump only for package aws-amplify-react -## [2.3.9-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.9-unstable.0...aws-amplify-react@2.3.9-unstable.1) (2019-05-31) - - +## [2.3.9-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.9-unstable.0...aws-amplify-react@2.3.9-unstable.1) (2019-05-31) **Note:** Version bump only for package aws-amplify-react -## [2.3.9-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.8...aws-amplify-react@2.3.9-unstable.0) (2019-05-24) +## [2.3.9-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.8...aws-amplify-react@2.3.9-unstable.0) (2019-05-24) ### Bug Fixes -* German localisation ([80c87ea](https://github.com/aws/aws-amplify/commit/80c87ea)) -* **aws-amplify-react:** adds e.preventDefault to confirm function in ConfirmSignIn component to prevent page reload ([b4ee413](https://github.com/aws/aws-amplify/commit/b4ee413)) -* **aws-amplify-react:** Fix typo in german localisation ([a5592f2](https://github.com/aws/aws-amplify/commit/a5592f2)) - +- German localisation ([80c87ea](https://github.com/aws/aws-amplify/commit/80c87ea)) +- **aws-amplify-react:** adds e.preventDefault to confirm function in ConfirmSignIn component to prevent page reload ([b4ee413](https://github.com/aws/aws-amplify/commit/b4ee413)) +- **aws-amplify-react:** Fix typo in german localisation ([a5592f2](https://github.com/aws/aws-amplify/commit/a5592f2)) ### Features -* **aws-amplify-react:** allow user to sign up with email or phone number ([b81f89e](https://github.com/aws/aws-amplify/commit/b81f89e)) - - - +- **aws-amplify-react:** allow user to sign up with email or phone number ([b81f89e](https://github.com/aws/aws-amplify/commit/b81f89e)) -## [2.3.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.8-unstable.1...aws-amplify-react@2.3.8) (2019-05-14) - - +## [2.3.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.8-unstable.1...aws-amplify-react@2.3.8) (2019-05-14) **Note:** Version bump only for package aws-amplify-react -## [2.3.8-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.8-unstable.0...aws-amplify-react@2.3.8-unstable.1) (2019-05-14) - - +## [2.3.8-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.8-unstable.0...aws-amplify-react@2.3.8-unstable.1) (2019-05-14) **Note:** Version bump only for package aws-amplify-react -## [2.3.8-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7...aws-amplify-react@2.3.8-unstable.0) (2019-05-13) +## [2.3.8-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7...aws-amplify-react@2.3.8-unstable.0) (2019-05-13) ### Bug Fixes -* add a todo to the greeting object in order to adjust the Angular Greeting Component to match React, fix typo in requireNewPassword ([49eae14](https://github.com/aws/aws-amplify/commit/49eae14)) - - - +- add a todo to the greeting object in order to adjust the Angular Greeting Component to match React, fix typo in requireNewPassword ([49eae14](https://github.com/aws/aws-amplify/commit/49eae14)) -## [2.3.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7-unstable.4...aws-amplify-react@2.3.7) (2019-05-06) - - +## [2.3.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7-unstable.4...aws-amplify-react@2.3.7) (2019-05-06) **Note:** Version bump only for package aws-amplify-react -## [2.3.7-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7-unstable.3...aws-amplify-react@2.3.7-unstable.4) (2019-04-26) - - +## [2.3.7-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7-unstable.3...aws-amplify-react@2.3.7-unstable.4) (2019-04-26) **Note:** Version bump only for package aws-amplify-react -## [2.3.7-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7-unstable.2...aws-amplify-react@2.3.7-unstable.3) (2019-04-24) - - +## [2.3.7-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7-unstable.2...aws-amplify-react@2.3.7-unstable.3) (2019-04-24) **Note:** Version bump only for package aws-amplify-react -## [2.3.7-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7-unstable.1...aws-amplify-react@2.3.7-unstable.2) (2019-04-19) - - +## [2.3.7-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7-unstable.1...aws-amplify-react@2.3.7-unstable.2) (2019-04-19) **Note:** Version bump only for package aws-amplify-react -## [2.3.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7-unstable.0...aws-amplify-react@2.3.7-unstable.1) (2019-04-19) - - +## [2.3.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.7-unstable.0...aws-amplify-react@2.3.7-unstable.1) (2019-04-19) **Note:** Version bump only for package aws-amplify-react -## [2.3.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.6...aws-amplify-react@2.3.7-unstable.0) (2019-04-16) - - +## [2.3.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.6...aws-amplify-react@2.3.7-unstable.0) (2019-04-16) **Note:** Version bump only for package aws-amplify-react -## [2.3.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.6-unstable.0...aws-amplify-react@2.3.6) (2019-04-11) - - +## [2.3.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.6-unstable.0...aws-amplify-react@2.3.6) (2019-04-11) **Note:** Version bump only for package aws-amplify-react -## [2.3.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.5...aws-amplify-react@2.3.6-unstable.0) (2019-04-10) +## [2.3.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.5...aws-amplify-react@2.3.6-unstable.0) (2019-04-10) ### Bug Fixes -* **@aws-amplify/auth:** Valide OAuth state only when generated by Amlify ([#3069](https://github.com/aws/aws-amplify/issues/3069)) ([30e828f](https://github.com/aws/aws-amplify/commit/30e828f)), closes [#3054](https://github.com/aws/aws-amplify/issues/3054) [#3055](https://github.com/aws/aws-amplify/issues/3055) - - - +- **@aws-amplify/auth:** Valide OAuth state only when generated by Amlify ([#3069](https://github.com/aws/aws-amplify/issues/3069)) ([30e828f](https://github.com/aws/aws-amplify/commit/30e828f)), closes [#3054](https://github.com/aws/aws-amplify/issues/3054) [#3055](https://github.com/aws/aws-amplify/issues/3055) -## [2.3.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.5-unstable.1...aws-amplify-react@2.3.5) (2019-04-09) - - +## [2.3.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.5-unstable.1...aws-amplify-react@2.3.5) (2019-04-09) **Note:** Version bump only for package aws-amplify-react -## [2.3.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.5-unstable.0...aws-amplify-react@2.3.5-unstable.1) (2019-04-08) +## [2.3.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.5-unstable.0...aws-amplify-react@2.3.5-unstable.1) (2019-04-08) ### Features -* **@aws-amplify/auth:** Easier Federation with OAuth ([#3005](https://github.com/aws/aws-amplify/issues/3005)) ([76cde59](https://github.com/aws/aws-amplify/commit/76cde59)) - - - +- **@aws-amplify/auth:** Easier Federation with OAuth ([#3005](https://github.com/aws/aws-amplify/issues/3005)) ([76cde59](https://github.com/aws/aws-amplify/commit/76cde59)) -## [2.3.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.4...aws-amplify-react@2.3.5-unstable.0) (2019-04-04) +## [2.3.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.4...aws-amplify-react@2.3.5-unstable.0) (2019-04-04) ### Bug Fixes -* update cypress version and fix auth text check ([4fb2356](https://github.com/aws/aws-amplify/commit/4fb2356)) - - - +- update cypress version and fix auth text check ([4fb2356](https://github.com/aws/aws-amplify/commit/4fb2356)) -## [2.3.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.4-unstable.1...aws-amplify-react@2.3.4) (2019-04-04) - - +## [2.3.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.4-unstable.1...aws-amplify-react@2.3.4) (2019-04-04) **Note:** Version bump only for package aws-amplify-react -## [2.3.4-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.4-unstable.0...aws-amplify-react@2.3.4-unstable.1) (2019-04-02) +## [2.3.4-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.4-unstable.0...aws-amplify-react@2.3.4-unstable.1) (2019-04-02) ### Bug Fixes -* check is component is mounted ([47ae0b9](https://github.com/aws/aws-amplify/commit/47ae0b9)) - - - +- check is component is mounted ([47ae0b9](https://github.com/aws/aws-amplify/commit/47ae0b9)) -## [2.3.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3...aws-amplify-react@2.3.4-unstable.0) (2019-03-29) - - +## [2.3.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3...aws-amplify-react@2.3.4-unstable.0) (2019-03-29) **Note:** Version bump only for package aws-amplify-react -## [2.3.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.8...aws-amplify-react@2.3.3) (2019-03-28) - - +## [2.3.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.8...aws-amplify-react@2.3.3) (2019-03-28) **Note:** Version bump only for package aws-amplify-react -## [2.3.3-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.7...aws-amplify-react@2.3.3-unstable.8) (2019-03-28) - - +## [2.3.3-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.7...aws-amplify-react@2.3.3-unstable.8) (2019-03-28) **Note:** Version bump only for package aws-amplify-react -## [2.3.3-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.6...aws-amplify-react@2.3.3-unstable.7) (2019-03-26) +## [2.3.3-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.6...aws-amplify-react@2.3.3-unstable.7) (2019-03-26) ### Bug Fixes -* **aws-amplify-react:** the username should not be undefined ([5ebddcb](https://github.com/aws/aws-amplify/commit/5ebddcb)) - - - +- **aws-amplify-react:** the username should not be undefined ([5ebddcb](https://github.com/aws/aws-amplify/commit/5ebddcb)) -## [2.3.3-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.5...aws-amplify-react@2.3.3-unstable.6) (2019-03-23) - - +## [2.3.3-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.5...aws-amplify-react@2.3.3-unstable.6) (2019-03-23) **Note:** Version bump only for package aws-amplify-react -## [2.3.3-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.4...aws-amplify-react@2.3.3-unstable.5) (2019-03-22) - - +## [2.3.3-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.4...aws-amplify-react@2.3.3-unstable.5) (2019-03-22) **Note:** Version bump only for package aws-amplify-react -## [2.3.3-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.3...aws-amplify-react@2.3.3-unstable.4) (2019-03-22) +## [2.3.3-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.3...aws-amplify-react@2.3.3-unstable.4) (2019-03-22) ### Bug Fixes -* **core:** Remove unneeded Hub.dispatch and Hub.listen ([#2919](https://github.com/aws/aws-amplify/issues/2919)) ([aea7fa9](https://github.com/aws/aws-amplify/commit/aea7fa9)), closes [#2623](https://github.com/aws/aws-amplify/issues/2623) - - - +- **core:** Remove unneeded Hub.dispatch and Hub.listen ([#2919](https://github.com/aws/aws-amplify/issues/2919)) ([aea7fa9](https://github.com/aws/aws-amplify/commit/aea7fa9)), closes [#2623](https://github.com/aws/aws-amplify/issues/2623) -## [2.3.3-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.2...aws-amplify-react@2.3.3-unstable.3) (2019-03-20) - - +## [2.3.3-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.2...aws-amplify-react@2.3.3-unstable.3) (2019-03-20) **Note:** Version bump only for package aws-amplify-react -## [2.3.3-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.1...aws-amplify-react@2.3.3-unstable.2) (2019-03-19) +## [2.3.3-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.1...aws-amplify-react@2.3.3-unstable.2) (2019-03-19) ### Bug Fixes -* remove stray semicolon after app wrapper ([d2d5fa3](https://github.com/aws/aws-amplify/commit/d2d5fa3)) - - - +- remove stray semicolon after app wrapper ([d2d5fa3](https://github.com/aws/aws-amplify/commit/d2d5fa3)) -## [2.3.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.0...aws-amplify-react@2.3.3-unstable.1) (2019-03-14) +## [2.3.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.3-unstable.0...aws-amplify-react@2.3.3-unstable.1) (2019-03-14) ### Bug Fixes -* **aws-amplify-react:** use
for the login component ([8f94b32](https://github.com/aws/aws-amplify/commit/8f94b32)) - - - +- **aws-amplify-react:** use for the login component ([8f94b32](https://github.com/aws/aws-amplify/commit/8f94b32)) -## [2.3.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.2...aws-amplify-react@2.3.3-unstable.0) (2019-03-11) - - +## [2.3.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.2...aws-amplify-react@2.3.3-unstable.0) (2019-03-11) **Note:** Version bump only for package aws-amplify-react -## [2.3.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.2-unstable.0...aws-amplify-react@2.3.2) (2019-03-06) - - +## [2.3.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.2-unstable.0...aws-amplify-react@2.3.2) (2019-03-06) **Note:** Version bump only for package aws-amplify-react -## [2.3.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1...aws-amplify-react@2.3.2-unstable.0) (2019-03-05) - - +## [2.3.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1...aws-amplify-react@2.3.2-unstable.0) (2019-03-05) **Note:** Version bump only for package aws-amplify-react -## [2.3.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.5...aws-amplify-react@2.3.1) (2019-03-04) - - +## [2.3.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.5...aws-amplify-react@2.3.1) (2019-03-04) **Note:** Version bump only for package aws-amplify-react -## [2.3.1-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.4...aws-amplify-react@2.3.1-unstable.5) (2019-03-04) +## [2.3.1-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.4...aws-amplify-react@2.3.1-unstable.5) (2019-03-04) ### Features -* **aws-amplify-react-native:** Add withOAuth HOC for Cognito Hosted UI ([#2665](https://github.com/aws/aws-amplify/issues/2665)) ([ac4d232](https://github.com/aws/aws-amplify/commit/ac4d232)) - - - +- **aws-amplify-react-native:** Add withOAuth HOC for Cognito Hosted UI ([#2665](https://github.com/aws/aws-amplify/issues/2665)) ([ac4d232](https://github.com/aws/aws-amplify/commit/ac4d232)) -## [2.3.1-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.3...aws-amplify-react@2.3.1-unstable.4) (2019-03-04) - - +## [2.3.1-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.3...aws-amplify-react@2.3.1-unstable.4) (2019-03-04) **Note:** Version bump only for package aws-amplify-react -## [2.3.1-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.2...aws-amplify-react@2.3.1-unstable.3) (2019-03-02) - - +## [2.3.1-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.2...aws-amplify-react@2.3.1-unstable.3) (2019-03-02) **Note:** Version bump only for package aws-amplify-react -## [2.3.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.1...aws-amplify-react@2.3.1-unstable.2) (2019-02-27) - - +## [2.3.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.1...aws-amplify-react@2.3.1-unstable.2) (2019-02-27) **Note:** Version bump only for package aws-amplify-react -## [2.3.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.0...aws-amplify-react@2.3.1-unstable.1) (2019-02-11) - - +## [2.3.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.1-unstable.0...aws-amplify-react@2.3.1-unstable.1) (2019-02-11) **Note:** Version bump only for package aws-amplify-react -## [2.3.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.0...aws-amplify-react@2.3.1-unstable.0) (2019-01-18) - - +## [2.3.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.3.0...aws-amplify-react@2.3.1-unstable.0) (2019-01-18) **Note:** Version bump only for package aws-amplify-react -# [2.3.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.6-unstable.1...aws-amplify-react@2.3.0) (2019-01-10) +# [2.3.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.6-unstable.1...aws-amplify-react@2.3.0) (2019-01-10) ### Features -* **aws-amplify-react:** add identityId prop to S3Album, S3Image, S3Text ([#2459](https://github.com/aws/aws-amplify/issues/2459)) ([26e1345](https://github.com/aws/aws-amplify/commit/26e1345)), closes [#2424](https://github.com/aws/aws-amplify/issues/2424) - - - +- **aws-amplify-react:** add identityId prop to S3Album, S3Image, S3Text ([#2459](https://github.com/aws/aws-amplify/issues/2459)) ([26e1345](https://github.com/aws/aws-amplify/commit/26e1345)), closes [#2424](https://github.com/aws/aws-amplify/issues/2424) -## [2.2.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.6-unstable.0...aws-amplify-react@2.2.6-unstable.1) (2018-12-28) - - +## [2.2.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.6-unstable.0...aws-amplify-react@2.2.6-unstable.1) (2018-12-28) **Note:** Version bump only for package aws-amplify-react -## [2.2.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.5...aws-amplify-react@2.2.6-unstable.0) (2018-12-28) +## [2.2.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.5...aws-amplify-react@2.2.6-unstable.0) (2018-12-28) ### Bug Fixes -* **aws-amplify-react:** transfer the children object to array ([b734d99](https://github.com/aws/aws-amplify/commit/b734d99)) - - - +- **aws-amplify-react:** transfer the children object to array ([b734d99](https://github.com/aws/aws-amplify/commit/b734d99)) -## [2.2.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.5-unstable.1...aws-amplify-react@2.2.5) (2018-12-26) - - +## [2.2.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.5-unstable.1...aws-amplify-react@2.2.5) (2018-12-26) **Note:** Version bump only for package aws-amplify-react -## [2.2.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.5-unstable.0...aws-amplify-react@2.2.5-unstable.1) (2018-12-24) - - +## [2.2.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.5-unstable.0...aws-amplify-react@2.2.5-unstable.1) (2018-12-24) **Note:** Version bump only for package aws-amplify-react -## [2.2.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.4...aws-amplify-react@2.2.5-unstable.0) (2018-12-19) - - +## [2.2.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.4...aws-amplify-react@2.2.5-unstable.0) (2018-12-19) **Note:** Version bump only for package aws-amplify-react -## [2.2.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.3-unstable.2...aws-amplify-react@2.2.4) (2018-12-15) - - +## [2.2.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.3-unstable.2...aws-amplify-react@2.2.4) (2018-12-15) **Note:** Version bump only for package aws-amplify-react + ## [2.2.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.2...aws-amplify-react@2.2.3) (2018-12-14) -## [2.2.3-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.3-unstable.1...aws-amplify-react@2.2.3-unstable.2) (2018-12-14) - - +## [2.2.3-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.3-unstable.1...aws-amplify-react@2.2.3-unstable.2) (2018-12-14) **Note:** Version bump only for package aws-amplify-react -## [2.2.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.3-unstable.0...aws-amplify-react@2.2.3-unstable.1) (2018-12-14) - - +## [2.2.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.3-unstable.0...aws-amplify-react@2.2.3-unstable.1) (2018-12-14) **Note:** Version bump only for package aws-amplify-react -## [2.2.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.2...aws-amplify-react@2.2.3-unstable.0) (2018-12-14) - - +## [2.2.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.2...aws-amplify-react@2.2.3-unstable.0) (2018-12-14) **Note:** Version bump only for package aws-amplify-react -## [2.2.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.2-unstable.1...aws-amplify-react@2.2.2) (2018-12-14) - - +## [2.2.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.2-unstable.1...aws-amplify-react@2.2.2) (2018-12-14) **Note:** Version bump only for package aws-amplify-react -## [2.2.2-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.2-unstable.0...aws-amplify-react@2.2.2-unstable.1) (2018-12-14) - - +## [2.2.2-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.2-unstable.0...aws-amplify-react@2.2.2-unstable.1) (2018-12-14) **Note:** Version bump only for package aws-amplify-react -## [2.2.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1...aws-amplify-react@2.2.2-unstable.0) (2018-12-13) +## [2.2.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1...aws-amplify-react@2.2.2-unstable.0) (2018-12-13) ### Features -* **@aws-amplify/interactions @aws-amplify/react @aws-amplify/react-native @aws-amplify/angular @aws-amplify/vue:** Update interactions to include voice ([#2121](https://github.com/aws/aws-amplify/issues/2121)) ([938d2a5](https://github.com/aws/aws-amplify/commit/938d2a5)) - - - +- **@aws-amplify/interactions @aws-amplify/react @aws-amplify/react-native @aws-amplify/angular @aws-amplify/vue:** Update interactions to include voice ([#2121](https://github.com/aws/aws-amplify/issues/2121)) ([938d2a5](https://github.com/aws/aws-amplify/commit/938d2a5)) -## [2.2.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-unstable.2...aws-amplify-react@2.2.1) (2018-12-13) - - +## [2.2.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-unstable.2...aws-amplify-react@2.2.1) (2018-12-13) **Note:** Version bump only for package aws-amplify-react -## [2.2.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-unstable.1...aws-amplify-react@2.2.1-unstable.2) (2018-12-13) +## [2.2.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-unstable.1...aws-amplify-react@2.2.1-unstable.2) (2018-12-13) ### Bug Fixes -* **aws-amplify-react:** fix instances of missing theme prop ([77904be](https://github.com/aws/aws-amplify/commit/77904be)) - - - +- **aws-amplify-react:** fix instances of missing theme prop ([77904be](https://github.com/aws/aws-amplify/commit/77904be)) -## [2.2.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-unstable.0...aws-amplify-react@2.2.1-unstable.1) (2018-12-11) - - +## [2.2.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-unstable.0...aws-amplify-react@2.2.1-unstable.1) (2018-12-11) **Note:** Version bump only for package aws-amplify-react -## [2.2.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.8-unstable.0...aws-amplify-react@2.2.1-unstable.0) (2018-12-10) - - +## [2.2.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.8-unstable.0...aws-amplify-react@2.2.1-unstable.0) (2018-12-10) **Note:** Version bump only for package aws-amplify-react -## [2.1.8-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.7...aws-amplify-react@2.1.8-unstable.0) (2018-12-07) - - +## [2.1.8-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.7...aws-amplify-react@2.1.8-unstable.0) (2018-12-07) **Note:** Version bump only for package aws-amplify-react -## [2.1.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.6...aws-amplify-react@2.1.7) (2018-12-07) - - +## [2.1.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.6...aws-amplify-react@2.1.7) (2018-12-07) **Note:** Version bump only for package aws-amplify-react -## [2.1.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.7-unstable.0...aws-amplify-react@2.1.7-unstable.1) (2018-12-06) +## [2.1.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.7-unstable.0...aws-amplify-react@2.1.7-unstable.1) (2018-12-06) ### Bug Fixes -* **aws-amplify-react:** correctly hide links under production mode ([8a52918](https://github.com/aws/aws-amplify/commit/8a52918)) - - - +- **aws-amplify-react:** correctly hide links under production mode ([8a52918](https://github.com/aws/aws-amplify/commit/8a52918)) -## [2.1.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.6...aws-amplify-react@2.1.7-unstable.0) (2018-12-06) - - +## [2.1.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.6...aws-amplify-react@2.1.7-unstable.0) (2018-12-06) **Note:** Version bump only for package aws-amplify-react -## [2.1.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5...aws-amplify-react@2.1.6) (2018-12-06) - - +## [2.1.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5...aws-amplify-react@2.1.6) (2018-12-06) **Note:** Version bump only for package aws-amplify-react -## [2.1.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.6-unstable.0...aws-amplify-react@2.1.6-unstable.1) (2018-12-05) +## [2.1.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.6-unstable.0...aws-amplify-react@2.1.6-unstable.1) (2018-12-05) ### Bug Fixes -* **aws-amplify-react:** authData in Greetings ([a1fef5b](https://github.com/aws/aws-amplify/commit/a1fef5b)) - - - +- **aws-amplify-react:** authData in Greetings ([a1fef5b](https://github.com/aws/aws-amplify/commit/a1fef5b)) -## [2.1.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5...aws-amplify-react@2.1.6-unstable.0) (2018-12-04) - - +## [2.1.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5...aws-amplify-react@2.1.6-unstable.0) (2018-12-04) **Note:** Version bump only for package aws-amplify-react -## [2.1.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.7...aws-amplify-react@2.1.5) (2018-12-03) - - +## [2.1.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.7...aws-amplify-react@2.1.5) (2018-12-03) **Note:** Version bump only for package aws-amplify-react -## [2.1.5-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.6...aws-amplify-react@2.1.5-unstable.7) (2018-12-03) - - +## [2.1.5-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.6...aws-amplify-react@2.1.5-unstable.7) (2018-12-03) **Note:** Version bump only for package aws-amplify-react -## [2.1.5-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.5...aws-amplify-react@2.1.5-unstable.6) (2018-11-30) +## [2.1.5-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.5...aws-amplify-react@2.1.5-unstable.6) (2018-11-30) ### Features -* **aws-amplify-react:** disable sign in button while loading ([#2216](https://github.com/aws/aws-amplify/issues/2216)) ([b196b7f](https://github.com/aws/aws-amplify/commit/b196b7f)) - +- **aws-amplify-react:** disable sign in button while loading ([#2216](https://github.com/aws/aws-amplify/issues/2216)) ([b196b7f](https://github.com/aws/aws-amplify/commit/b196b7f)) -## [2.1.5-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.4...aws-amplify-react@2.1.5-unstable.5) (2018-11-26) +## [2.1.5-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.4...aws-amplify-react@2.1.5-unstable.5) (2018-11-26) **Note:** Version bump only for package aws-amplify-react -## [2.1.5-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.3...aws-amplify-react@2.1.5-unstable.4) (2018-11-23) +## [2.1.5-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.3...aws-amplify-react@2.1.5-unstable.4) (2018-11-23) ### Bug Fixes -* **aws-amplify-react:** add I18n in Greetings ([e549db7](https://github.com/aws/aws-amplify/commit/e549db7)) +- **aws-amplify-react:** add I18n in Greetings ([e549db7](https://github.com/aws/aws-amplify/commit/e549db7)) -## [2.1.5-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.2...aws-amplify-react@2.1.5-unstable.3) (2018-11-21) +## [2.1.5-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.2...aws-amplify-react@2.1.5-unstable.3) (2018-11-21) **Note:** Version bump only for package aws-amplify-react -## [2.1.5-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.1...aws-amplify-react@2.1.5-unstable.2) (2018-11-21) - +## [2.1.5-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.1...aws-amplify-react@2.1.5-unstable.2) (2018-11-21) **Note:** Version bump only for package aws-amplify-react -## [2.2.1-beta.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-beta.4...aws-amplify-react@2.2.1-beta.5) (2018-11-19) +## [2.2.1-beta.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-beta.4...aws-amplify-react@2.2.1-beta.5) (2018-11-19) **Note:** Version bump only for package aws-amplify-react -## [2.1.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.0...aws-amplify-react@2.1.5-unstable.1) (2018-11-19) - +## [2.1.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.5-unstable.0...aws-amplify-react@2.1.5-unstable.1) (2018-11-19) **Note:** Version bump only for package aws-amplify-react -## [2.1.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4...aws-amplify-react@2.1.5-unstable.0) (2018-11-16) - +## [2.1.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4...aws-amplify-react@2.1.5-unstable.0) (2018-11-16) **Note:** Version bump only for package aws-amplify-react -## [2.2.1-beta.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-beta.3...aws-amplify-react@2.2.1-beta.4) (2018-11-15) - +## [2.2.1-beta.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-beta.3...aws-amplify-react@2.2.1-beta.4) (2018-11-15) **Note:** Version bump only for package aws-amplify-react -## [2.2.1-beta.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-beta.2...aws-amplify-react@2.2.1-beta.3) (2018-11-14) +## [2.2.1-beta.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.2.1-beta.2...aws-amplify-react@2.2.1-beta.3) (2018-11-14) -## [2.2.1-beta.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.4...aws-amplify-react@2.2.1-beta.2) (2018-11-14) +## [2.2.1-beta.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.4...aws-amplify-react@2.2.1-beta.2) (2018-11-14) ### Bug Fixes -* **aws-amplify-react:** check if gapi is inited when mounting the component ([9a7d306](https://github.com/aws/aws-amplify/commit/9a7d306)) - +- **aws-amplify-react:** check if gapi is inited when mounting the component ([9a7d306](https://github.com/aws/aws-amplify/commit/9a7d306)) -## [2.1.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.4...aws-amplify-react@2.1.4) (2018-11-12) - - - +## [2.1.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.4...aws-amplify-react@2.1.4) (2018-11-12) **Note:** Version bump only for package aws-amplify-react -## [2.1.4-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.3...aws-amplify-react@2.1.4-unstable.4) (2018-11-09) +## [2.1.4-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.3...aws-amplify-react@2.1.4-unstable.4) (2018-11-09) ### Features -* **aws-amplify-react:** adding loading page ([c47f72a](https://github.com/aws/aws-amplify/commit/c47f72a)) - - - +- **aws-amplify-react:** adding loading page ([c47f72a](https://github.com/aws/aws-amplify/commit/c47f72a)) -## [2.1.4-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.2...aws-amplify-react@2.1.4-unstable.3) (2018-11-08) +## [2.1.4-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.2...aws-amplify-react@2.1.4-unstable.3) (2018-11-08) ### Bug Fixes -* **aws-amplify-react:** change the way to import qrcode ([8afd5dd](https://github.com/aws/aws-amplify/commit/8afd5dd)) - - - +- **aws-amplify-react:** change the way to import qrcode ([8afd5dd](https://github.com/aws/aws-amplify/commit/8afd5dd)) -## [2.1.4-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.1...aws-amplify-react@2.1.4-unstable.2) (2018-11-07) +## [2.1.4-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.1...aws-amplify-react@2.1.4-unstable.2) (2018-11-07) ### Bug Fixes -* **aws-amplify-react:** change to forgetpassword state if need to reset password ([0c1e994](https://github.com/aws/aws-amplify/commit/0c1e994)) - - - +- **aws-amplify-react:** change to forgetpassword state if need to reset password ([0c1e994](https://github.com/aws/aws-amplify/commit/0c1e994)) -## [2.1.4-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.0...aws-amplify-react@2.1.4-unstable.1) (2018-11-06) +## [2.1.4-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.4-unstable.0...aws-amplify-react@2.1.4-unstable.1) (2018-11-06) ### Bug Fixes -* **aws-amplify-react:** only call Auth signOut if some error happens during signed in ([1ceb3ef](https://github.com/aws/aws-amplify/commit/1ceb3ef)) - - - +- **aws-amplify-react:** only call Auth signOut if some error happens during signed in ([1ceb3ef](https://github.com/aws/aws-amplify/commit/1ceb3ef)) -## [2.1.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3...aws-amplify-react@2.1.4-unstable.0) (2018-11-05) - - +## [2.1.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3...aws-amplify-react@2.1.4-unstable.0) (2018-11-05) **Note:** Version bump only for package aws-amplify-react -## [2.1.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3-unstable.4...aws-amplify-react@2.1.3) (2018-11-01) - - +## [2.1.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3-unstable.4...aws-amplify-react@2.1.3) (2018-11-01) **Note:** Version bump only for package aws-amplify-react -## [2.1.3-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3-unstable.3...aws-amplify-react@2.1.3-unstable.4) (2018-11-01) - - +## [2.1.3-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3-unstable.3...aws-amplify-react@2.1.3-unstable.4) (2018-11-01) **Note:** Version bump only for package aws-amplify-react -## [2.1.3-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3-unstable.2...aws-amplify-react@2.1.3-unstable.3) (2018-10-31) +## [2.1.3-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3-unstable.2...aws-amplify-react@2.1.3-unstable.3) (2018-10-31) ### Bug Fixes -* **@aws-amplify/auth:** Adding theme support to the FederatedButtons "or" Strike ([554c1fc](https://github.com/aws/aws-amplify/commit/554c1fc)) - - - +- **@aws-amplify/auth:** Adding theme support to the FederatedButtons "or" Strike ([554c1fc](https://github.com/aws/aws-amplify/commit/554c1fc)) -## [2.1.3-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3-unstable.1...aws-amplify-react@2.1.3-unstable.2) (2018-10-30) - - +## [2.1.3-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3-unstable.1...aws-amplify-react@2.1.3-unstable.2) (2018-10-30) **Note:** Version bump only for package aws-amplify-react -## [2.1.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3-unstable.0...aws-amplify-react@2.1.3-unstable.1) (2018-10-30) - - +## [2.1.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.3-unstable.0...aws-amplify-react@2.1.3-unstable.1) (2018-10-30) **Note:** Version bump only for package aws-amplify-react -## [2.1.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2...aws-amplify-react@2.1.3-unstable.0) (2018-10-30) - - +## [2.1.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2...aws-amplify-react@2.1.3-unstable.0) (2018-10-30) **Note:** Version bump only for package aws-amplify-react -## [2.1.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.5...aws-amplify-react@2.1.2) (2018-10-29) - - +## [2.1.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.5...aws-amplify-react@2.1.2) (2018-10-29) **Note:** Version bump only for package aws-amplify-react -## [2.1.2-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.4...aws-amplify-react@2.1.2-unstable.5) (2018-10-29) +## [2.1.2-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.4...aws-amplify-react@2.1.2-unstable.5) (2018-10-29) ### Bug Fixes -* **aws-amplify-react:** show the link of create account when using customized signup component ([1b4de49](https://github.com/aws/aws-amplify/commit/1b4de49)) - - - +- **aws-amplify-react:** show the link of create account when using customized signup component ([1b4de49](https://github.com/aws/aws-amplify/commit/1b4de49)) -## [2.1.2-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.3...aws-amplify-react@2.1.2-unstable.4) (2018-10-29) +## [2.1.2-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.3...aws-amplify-react@2.1.2-unstable.4) (2018-10-29) ### Bug Fixes -* **aws-amplify-react:** pass the user name when signin error happens ([b857101](https://github.com/aws/aws-amplify/commit/b857101)) - - - +- **aws-amplify-react:** pass the user name when signin error happens ([b857101](https://github.com/aws/aws-amplify/commit/b857101)) -## [2.1.2-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.2...aws-amplify-react@2.1.2-unstable.3) (2018-10-29) +## [2.1.2-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.2...aws-amplify-react@2.1.2-unstable.3) (2018-10-29) ### Features -* **aws-amplify-react:** Add Auth0 button ([b16ded3](https://github.com/aws/aws-amplify/commit/b16ded3)) - - - +- **aws-amplify-react:** Add Auth0 button ([b16ded3](https://github.com/aws/aws-amplify/commit/b16ded3)) -## [2.1.2-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.1...aws-amplify-react@2.1.2-unstable.2) (2018-10-25) +## [2.1.2-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.1...aws-amplify-react@2.1.2-unstable.2) (2018-10-25) ### Features -* **aws-amplify-react:** federated sign out methods refactor ([9edbd6e](https://github.com/aws/aws-amplify/commit/9edbd6e)) - - - +- **aws-amplify-react:** federated sign out methods refactor ([9edbd6e](https://github.com/aws/aws-amplify/commit/9edbd6e)) -## [2.1.2-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.0...aws-amplify-react@2.1.2-unstable.1) (2018-10-25) +## [2.1.2-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.2-unstable.0...aws-amplify-react@2.1.2-unstable.1) (2018-10-25) ### Bug Fixes -* **aws-amplify-react aws-amplify-react-native:** Connect component ([#1868](https://github.com/aws/aws-amplify/issues/1868)) ([8dd6b55](https://github.com/aws/aws-amplify/commit/8dd6b55)) - - - +- **aws-amplify-react aws-amplify-react-native:** Connect component ([#1868](https://github.com/aws/aws-amplify/issues/1868)) ([8dd6b55](https://github.com/aws/aws-amplify/commit/8dd6b55)) -## [2.1.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.1...aws-amplify-react@2.1.2-unstable.0) (2018-10-23) - - +## [2.1.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.1.1...aws-amplify-react@2.1.2-unstable.0) (2018-10-23) **Note:** Version bump only for package aws-amplify-react -## [2.1.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.8-unstable.2...aws-amplify-react@2.1.1) (2018-10-17) - - +## [2.1.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.8-unstable.2...aws-amplify-react@2.1.1) (2018-10-17) **Note:** Version bump only for package aws-amplify-react -## [2.0.8-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.8-unstable.1...aws-amplify-react@2.0.8-unstable.2) (2018-10-16) - - +## [2.0.8-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.8-unstable.1...aws-amplify-react@2.0.8-unstable.2) (2018-10-16) **Note:** Version bump only for package aws-amplify-react -## [2.0.8-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.8-unstable.0...aws-amplify-react@2.0.8-unstable.1) (2018-10-08) +## [2.0.8-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.8-unstable.0...aws-amplify-react@2.0.8-unstable.1) (2018-10-08) ### Bug Fixes -* **aws-amplify-react:** jump to the initial state if not signed in ([d8779eb](https://github.com/aws/aws-amplify/commit/d8779eb)) - - - +- **aws-amplify-react:** jump to the initial state if not signed in ([d8779eb](https://github.com/aws/aws-amplify/commit/d8779eb)) -## [2.0.8-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.7-unstable.1...aws-amplify-react@2.0.8-unstable.0) (2018-10-05) - - +## [2.0.8-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.7-unstable.1...aws-amplify-react@2.0.8-unstable.0) (2018-10-05) **Note:** Version bump only for package aws-amplify-react -## [2.0.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.7-unstable.1...aws-amplify-react@2.0.7) (2018-10-04) - - +## [2.0.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.7-unstable.1...aws-amplify-react@2.0.7) (2018-10-04) **Note:** Version bump only for package aws-amplify-react -## [2.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.7-unstable.0...aws-amplify-react@2.0.7-unstable.1) (2018-10-03) - - +## [2.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.7-unstable.0...aws-amplify-react@2.0.7-unstable.1) (2018-10-03) **Note:** Version bump only for package aws-amplify-react -## [2.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.6-unstable.1...aws-amplify-react@2.0.7-unstable.0) (2018-10-03) - - +## [2.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.6-unstable.1...aws-amplify-react@2.0.7-unstable.0) (2018-10-03) **Note:** Version bump only for package aws-amplify-react -## [2.0.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.6-unstable.1...aws-amplify-react@2.0.6) (2018-10-03) - - +## [2.0.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.6-unstable.1...aws-amplify-react@2.0.6) (2018-10-03) **Note:** Version bump only for package aws-amplify-react -## [2.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.6-unstable.0...aws-amplify-react@2.0.6-unstable.1) (2018-10-02) - - +## [2.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.6-unstable.0...aws-amplify-react@2.0.6-unstable.1) (2018-10-02) **Note:** Version bump only for package aws-amplify-react -## [2.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.5...aws-amplify-react@2.0.6-unstable.0) (2018-10-02) - - +## [2.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.5...aws-amplify-react@2.0.6-unstable.0) (2018-10-02) **Note:** Version bump only for package aws-amplify-react -## [2.0.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.5-unstable.1...aws-amplify-react@2.0.5) (2018-09-27) - - +## [2.0.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.5-unstable.1...aws-amplify-react@2.0.5) (2018-09-27) **Note:** Version bump only for package aws-amplify-react -## [2.0.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.5-unstable.0...aws-amplify-react@2.0.5-unstable.1) (2018-09-26) - - +## [2.0.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.5-unstable.0...aws-amplify-react@2.0.5-unstable.1) (2018-09-26) **Note:** Version bump only for package aws-amplify-react -## [2.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.4...aws-amplify-react@2.0.5-unstable.0) (2018-09-26) - - +## [2.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.4...aws-amplify-react@2.0.5-unstable.0) (2018-09-26) **Note:** Version bump only for package aws-amplify-react -## [2.0.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.4-unstable.0...aws-amplify-react@2.0.4) (2018-09-21) - - +## [2.0.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.4-unstable.0...aws-amplify-react@2.0.4) (2018-09-21) **Note:** Version bump only for package aws-amplify-react -## [2.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.3-unstable.0...aws-amplify-react@2.0.4-unstable.0) (2018-09-21) - - +## [2.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.3-unstable.0...aws-amplify-react@2.0.4-unstable.0) (2018-09-21) **Note:** Version bump only for package aws-amplify-react -## [2.0.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.2...aws-amplify-react@2.0.3) (2018-09-21) - - +## [2.0.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.2...aws-amplify-react@2.0.3) (2018-09-21) **Note:** Version bump only for package aws-amplify-react -## [2.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.2...aws-amplify-react@2.0.3-unstable.0) (2018-09-20) +## [2.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.2...aws-amplify-react@2.0.3-unstable.0) (2018-09-20) ### Bug Fixes -* **aws-amplify-react:** Fix import statement ([#1695](https://github.com/aws/aws-amplify/issues/1695)) ([07bdfc2](https://github.com/aws/aws-amplify/commit/07bdfc2)), closes [#1482](https://github.com/aws/aws-amplify/issues/1482) [#1484](https://github.com/aws/aws-amplify/issues/1484) - - - +- **aws-amplify-react:** Fix import statement ([#1695](https://github.com/aws/aws-amplify/issues/1695)) ([07bdfc2](https://github.com/aws/aws-amplify/commit/07bdfc2)), closes [#1482](https://github.com/aws/aws-amplify/issues/1482) [#1484](https://github.com/aws/aws-amplify/issues/1484) -## [2.0.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.1...aws-amplify-react@2.0.2) (2018-09-17) +## [2.0.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.1...aws-amplify-react@2.0.2) (2018-09-17) ### Bug Fixes -* **@aws-amplify-react/auth:** handle required attributes in NEW_PASSWORD_REQUIRED challenge ([5ee6288](https://github.com/aws/aws-amplify/commit/5ee6288)) -* **aws-amplify-react:** fix PhotoPicker preview ([db3331e](https://github.com/aws/aws-amplify/commit/db3331e)) -* **aws-amplify-react:** fix the phone number format in sign up component ([a21d486](https://github.com/aws/aws-amplify/commit/a21d486)) - - - +- **@aws-amplify-react/auth:** handle required attributes in NEW_PASSWORD_REQUIRED challenge ([5ee6288](https://github.com/aws/aws-amplify/commit/5ee6288)) +- **aws-amplify-react:** fix PhotoPicker preview ([db3331e](https://github.com/aws/aws-amplify/commit/db3331e)) +- **aws-amplify-react:** fix the phone number format in sign up component ([a21d486](https://github.com/aws/aws-amplify/commit/a21d486)) -## [2.0.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.1-unstable.0...aws-amplify-react@2.0.1) (2018-09-09) - - +## [2.0.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.1-unstable.0...aws-amplify-react@2.0.1) (2018-09-09) **Note:** Version bump only for package aws-amplify-react -## [2.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.0...aws-amplify-react@2.0.1-unstable.0) (2018-09-07) +## [2.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@2.0.0...aws-amplify-react@2.0.1-unstable.0) (2018-09-07) ### Bug Fixes -* **aws-amplify-react:** fix the break change of federatedSignIn ([5ca239c](https://github.com/aws/aws-amplify/commit/5ca239c)) - - - +- **aws-amplify-react:** fix the break change of federatedSignIn ([5ca239c](https://github.com/aws/aws-amplify/commit/5ca239c)) -# [2.0.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.26...aws-amplify-react@2.0.0) (2018-08-28) +# [2.0.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.26...aws-amplify-react@2.0.0) (2018-08-28) ### Features -* UI Components ([1ff1abd](https://github.com/aws/aws-amplify/commit/1ff1abd)) - +- UI Components ([1ff1abd](https://github.com/aws/aws-amplify/commit/1ff1abd)) ### BREAKING CHANGES -* UI Components - - - +- UI Components -## [1.0.7-unstable.26](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.25...aws-amplify-react@1.0.7-unstable.26) (2018-08-28) - -* Amplify ui migration (#1517) ([41d3184](https://github.com/aws/aws-amplify/commit/41d3184)), closes [#1517](https://github.com/aws/aws-amplify/issues/1517) +## [1.0.7-unstable.26](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.25...aws-amplify-react@1.0.7-unstable.26) (2018-08-28) +- Amplify ui migration (#1517) ([41d3184](https://github.com/aws/aws-amplify/commit/41d3184)), closes [#1517](https://github.com/aws/aws-amplify/issues/1517) ### BREAKING CHANGES -* UI Components - - - +- UI Components -## [1.0.7-unstable.25](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.24...aws-amplify-react@1.0.7-unstable.25) (2018-08-27) - - +## [1.0.7-unstable.25](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.24...aws-amplify-react@1.0.7-unstable.25) (2018-08-27) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.24](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.23...aws-amplify-react@1.0.7-unstable.24) (2018-08-27) - - +## [1.0.7-unstable.24](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.23...aws-amplify-react@1.0.7-unstable.24) (2018-08-27) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.23](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.21...aws-amplify-react@1.0.7-unstable.23) (2018-08-27) - - +## [1.0.7-unstable.23](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.21...aws-amplify-react@1.0.7-unstable.23) (2018-08-27) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.22](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.21...aws-amplify-react@1.0.7-unstable.22) (2018-08-25) - - +## [1.0.7-unstable.22](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.21...aws-amplify-react@1.0.7-unstable.22) (2018-08-25) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.21](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.20...aws-amplify-react@1.0.7-unstable.21) (2018-08-24) - - +## [1.0.7-unstable.21](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.20...aws-amplify-react@1.0.7-unstable.21) (2018-08-24) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.20](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.19...aws-amplify-react@1.0.7-unstable.20) (2018-08-24) - - +## [1.0.7-unstable.20](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.19...aws-amplify-react@1.0.7-unstable.20) (2018-08-24) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.19](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.17...aws-amplify-react@1.0.7-unstable.19) (2018-08-24) - - +## [1.0.7-unstable.19](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.17...aws-amplify-react@1.0.7-unstable.19) (2018-08-24) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.18](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.17...aws-amplify-react@1.0.7-unstable.18) (2018-08-24) - - +## [1.0.7-unstable.18](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.17...aws-amplify-react@1.0.7-unstable.18) (2018-08-24) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.15...aws-amplify-react@1.0.7-unstable.17) (2018-08-24) - - +## [1.0.7-unstable.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.15...aws-amplify-react@1.0.7-unstable.17) (2018-08-24) **Note:** Version bump only for package aws-amplify-react - -## [1.0.7-unstable.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.15...aws-amplify-react@1.0.7-unstable.16) (2018-08-24) - - + +## [1.0.7-unstable.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.15...aws-amplify-react@1.0.7-unstable.16) (2018-08-24) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.14...aws-amplify-react@1.0.7-unstable.15) (2018-08-24) - - +## [1.0.7-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.14...aws-amplify-react@1.0.7-unstable.15) (2018-08-24) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.13...aws-amplify-react@1.0.7-unstable.14) (2018-08-24) - - +## [1.0.7-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.13...aws-amplify-react@1.0.7-unstable.14) (2018-08-24) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.11...aws-amplify-react@1.0.7-unstable.13) (2018-08-23) - - +## [1.0.7-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.11...aws-amplify-react@1.0.7-unstable.13) (2018-08-23) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.11...aws-amplify-react@1.0.7-unstable.12) (2018-08-23) - - +## [1.0.7-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.11...aws-amplify-react@1.0.7-unstable.12) (2018-08-23) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.10...aws-amplify-react@1.0.7-unstable.11) (2018-08-23) - - +## [1.0.7-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.10...aws-amplify-react@1.0.7-unstable.11) (2018-08-23) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.9...aws-amplify-react@1.0.7-unstable.10) (2018-08-23) - - +## [1.0.7-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.9...aws-amplify-react@1.0.7-unstable.10) (2018-08-23) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.8...aws-amplify-react@1.0.7-unstable.9) (2018-08-23) - - +## [1.0.7-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.8...aws-amplify-react@1.0.7-unstable.9) (2018-08-23) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.7...aws-amplify-react@1.0.7-unstable.8) (2018-08-22) - - +## [1.0.7-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.7...aws-amplify-react@1.0.7-unstable.8) (2018-08-22) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.6...aws-amplify-react@1.0.7-unstable.7) (2018-08-22) +## [1.0.7-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.6...aws-amplify-react@1.0.7-unstable.7) (2018-08-22) ### Bug Fixes -* **aws-amplify-react:** Fix import statement ([fe1826a](https://github.com/aws/aws-amplify/commit/fe1826a)), closes [#1482](https://github.com/aws/aws-amplify/issues/1482) - - - +- **aws-amplify-react:** Fix import statement ([fe1826a](https://github.com/aws/aws-amplify/commit/fe1826a)), closes [#1482](https://github.com/aws/aws-amplify/issues/1482) -## [1.0.7-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.5...aws-amplify-react@1.0.7-unstable.6) (2018-08-21) - - +## [1.0.7-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.5...aws-amplify-react@1.0.7-unstable.6) (2018-08-21) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.4...aws-amplify-react@1.0.7-unstable.5) (2018-08-21) - - +## [1.0.7-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.4...aws-amplify-react@1.0.7-unstable.5) (2018-08-21) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.3...aws-amplify-react@1.0.7-unstable.4) (2018-08-20) - - +## [1.0.7-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.3...aws-amplify-react@1.0.7-unstable.4) (2018-08-20) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.2...aws-amplify-react@1.0.7-unstable.3) (2018-08-19) +## [1.0.7-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.2...aws-amplify-react@1.0.7-unstable.3) (2018-08-19) ### Bug Fixes -* **aws-amplify-angular:** Angular rollup ([#1441](https://github.com/aws/aws-amplify/issues/1441)) ([eb84e01](https://github.com/aws/aws-amplify/commit/eb84e01)) - - - +- **aws-amplify-angular:** Angular rollup ([#1441](https://github.com/aws/aws-amplify/issues/1441)) ([eb84e01](https://github.com/aws/aws-amplify/commit/eb84e01)) -## [1.0.7-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.1...aws-amplify-react@1.0.7-unstable.2) (2018-08-18) - - +## [1.0.7-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.1...aws-amplify-react@1.0.7-unstable.2) (2018-08-18) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.0...aws-amplify-react@1.0.7-unstable.1) (2018-08-16) - - +## [1.0.7-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.7-unstable.0...aws-amplify-react@1.0.7-unstable.1) (2018-08-16) **Note:** Version bump only for package aws-amplify-react -## [1.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6...aws-amplify-react@1.0.7-unstable.0) (2018-08-15) - - +## [1.0.7-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6...aws-amplify-react@1.0.7-unstable.0) (2018-08-15) **Note:** Version bump only for package aws-amplify-react -## [1.0.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.5...aws-amplify-react@1.0.6) (2018-08-14) - - +## [1.0.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.5...aws-amplify-react@1.0.6) (2018-08-14) **Note:** Version bump only for package aws-amplify-react -## [1.0.6-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.4...aws-amplify-react@1.0.6-unstable.5) (2018-08-14) - - +## [1.0.6-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.4...aws-amplify-react@1.0.6-unstable.5) (2018-08-14) **Note:** Version bump only for package aws-amplify-react -## [1.0.6-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.3...aws-amplify-react@1.0.6-unstable.4) (2018-08-13) - - +## [1.0.6-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.3...aws-amplify-react@1.0.6-unstable.4) (2018-08-13) **Note:** Version bump only for package aws-amplify-react -## [1.0.6-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.2...aws-amplify-react@1.0.6-unstable.3) (2018-08-13) - - +## [1.0.6-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.2...aws-amplify-react@1.0.6-unstable.3) (2018-08-13) **Note:** Version bump only for package aws-amplify-react -## [1.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.1...aws-amplify-react@1.0.6-unstable.2) (2018-08-09) - - +## [1.0.6-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.1...aws-amplify-react@1.0.6-unstable.2) (2018-08-09) **Note:** Version bump only for package aws-amplify-react -## [1.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.0...aws-amplify-react@1.0.6-unstable.1) (2018-08-07) - - +## [1.0.6-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.6-unstable.0...aws-amplify-react@1.0.6-unstable.1) (2018-08-07) **Note:** Version bump only for package aws-amplify-react -## [1.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5...aws-amplify-react@1.0.6-unstable.0) (2018-08-07) - - +## [1.0.6-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5...aws-amplify-react@1.0.6-unstable.0) (2018-08-07) **Note:** Version bump only for package aws-amplify-react -## [1.0.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.7...aws-amplify-react@1.0.5) (2018-08-06) - - +## [1.0.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.7...aws-amplify-react@1.0.5) (2018-08-06) **Note:** Version bump only for package aws-amplify-react -## [1.0.5-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.6...aws-amplify-react@1.0.5-unstable.7) (2018-08-06) - - +## [1.0.5-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.6...aws-amplify-react@1.0.5-unstable.7) (2018-08-06) **Note:** Version bump only for package aws-amplify-react -## [1.0.5-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.5...aws-amplify-react@1.0.5-unstable.6) (2018-08-06) - - +## [1.0.5-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.5...aws-amplify-react@1.0.5-unstable.6) (2018-08-06) **Note:** Version bump only for package aws-amplify-react -## [1.0.5-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.3...aws-amplify-react@1.0.5-unstable.5) (2018-08-06) - - +## [1.0.5-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.3...aws-amplify-react@1.0.5-unstable.5) (2018-08-06) **Note:** Version bump only for package aws-amplify-react -## [1.0.5-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.2...aws-amplify-react@1.0.5-unstable.3) (2018-07-31) - - +## [1.0.5-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.2...aws-amplify-react@1.0.5-unstable.3) (2018-07-31) **Note:** Version bump only for package aws-amplify-react -## [1.0.5-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.1...aws-amplify-react@1.0.5-unstable.2) (2018-07-31) - - +## [1.0.5-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.1...aws-amplify-react@1.0.5-unstable.2) (2018-07-31) **Note:** Version bump only for package aws-amplify-react -## [1.0.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.0...aws-amplify-react@1.0.5-unstable.1) (2018-07-30) - - +## [1.0.5-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.5-unstable.0...aws-amplify-react@1.0.5-unstable.1) (2018-07-30) **Note:** Version bump only for package aws-amplify-react -## [1.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.4...aws-amplify-react@1.0.5-unstable.0) (2018-07-30) - - +## [1.0.5-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.4...aws-amplify-react@1.0.5-unstable.0) (2018-07-30) **Note:** Version bump only for package aws-amplify-react -## [1.0.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.4-unstable.1...aws-amplify-react@1.0.4) (2018-07-28) - - +## [1.0.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.4-unstable.1...aws-amplify-react@1.0.4) (2018-07-28) **Note:** Version bump only for package aws-amplify-react -## [1.0.4-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.4-unstable.0...aws-amplify-react@1.0.4-unstable.1) (2018-07-28) - - +## [1.0.4-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.4-unstable.0...aws-amplify-react@1.0.4-unstable.1) (2018-07-28) **Note:** Version bump only for package aws-amplify-react -## [1.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.14...aws-amplify-react@1.0.4-unstable.0) (2018-07-27) - - +## [1.0.4-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.14...aws-amplify-react@1.0.4-unstable.0) (2018-07-27) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.14...aws-amplify-react@1.0.3-unstable.15) (2018-07-27) - - +## [1.0.3-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.14...aws-amplify-react@1.0.3-unstable.15) (2018-07-27) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.13...aws-amplify-react@1.0.3-unstable.14) (2018-07-27) - - +## [1.0.3-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.13...aws-amplify-react@1.0.3-unstable.14) (2018-07-27) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.12...aws-amplify-react@1.0.3-unstable.13) (2018-07-26) - - +## [1.0.3-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.12...aws-amplify-react@1.0.3-unstable.13) (2018-07-26) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.11...aws-amplify-react@1.0.3-unstable.12) (2018-07-26) +## [1.0.3-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.11...aws-amplify-react@1.0.3-unstable.12) (2018-07-26) ### Bug Fixes -* **@aws-amplify/auth:** currentAuthenticatedUser throws error when the user is disabled/deleted ([1b09e2f](https://github.com/aws/aws-amplify/commit/1b09e2f)) - - - +- **@aws-amplify/auth:** currentAuthenticatedUser throws error when the user is disabled/deleted ([1b09e2f](https://github.com/aws/aws-amplify/commit/1b09e2f)) -## [1.0.3-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.10...aws-amplify-react@1.0.3-unstable.11) (2018-07-26) - - +## [1.0.3-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.10...aws-amplify-react@1.0.3-unstable.11) (2018-07-26) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.9...aws-amplify-react@1.0.3-unstable.10) (2018-07-26) - - +## [1.0.3-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.9...aws-amplify-react@1.0.3-unstable.10) (2018-07-26) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.8...aws-amplify-react@1.0.3-unstable.9) (2018-07-25) - - +## [1.0.3-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.8...aws-amplify-react@1.0.3-unstable.9) (2018-07-25) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.7...aws-amplify-react@1.0.3-unstable.8) (2018-07-25) - - +## [1.0.3-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.7...aws-amplify-react@1.0.3-unstable.8) (2018-07-25) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.6...aws-amplify-react@1.0.3-unstable.7) (2018-07-25) - - +## [1.0.3-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.6...aws-amplify-react@1.0.3-unstable.7) (2018-07-25) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.5...aws-amplify-react@1.0.3-unstable.6) (2018-07-24) - - +## [1.0.3-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.5...aws-amplify-react@1.0.3-unstable.6) (2018-07-24) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.4...aws-amplify-react@1.0.3-unstable.5) (2018-07-23) - - +## [1.0.3-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.4...aws-amplify-react@1.0.3-unstable.5) (2018-07-23) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.3...aws-amplify-react@1.0.3-unstable.4) (2018-07-23) - - +## [1.0.3-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.3...aws-amplify-react@1.0.3-unstable.4) (2018-07-23) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.2...aws-amplify-react@1.0.3-unstable.3) (2018-07-23) - - +## [1.0.3-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.2...aws-amplify-react@1.0.3-unstable.3) (2018-07-23) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.1...aws-amplify-react@1.0.3-unstable.2) (2018-07-20) - - +## [1.0.3-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.1...aws-amplify-react@1.0.3-unstable.2) (2018-07-20) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.0...aws-amplify-react@1.0.3-unstable.1) (2018-07-20) - - +## [1.0.3-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.3-unstable.0...aws-amplify-react@1.0.3-unstable.1) (2018-07-20) **Note:** Version bump only for package aws-amplify-react -## [1.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.2...aws-amplify-react@1.0.3-unstable.0) (2018-07-20) - - +## [1.0.3-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.2...aws-amplify-react@1.0.3-unstable.0) (2018-07-20) **Note:** Version bump only for package aws-amplify-react -## [1.0.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.2-unstable.1...aws-amplify-react@1.0.2) (2018-07-19) - - +## [1.0.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.2-unstable.1...aws-amplify-react@1.0.2) (2018-07-19) **Note:** Version bump only for package aws-amplify-react -## [1.0.2-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1...aws-amplify-react@1.0.2-unstable.1) (2018-07-19) - - +## [1.0.2-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1...aws-amplify-react@1.0.2-unstable.1) (2018-07-19) **Note:** Version bump only for package aws-amplify-react -## [1.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1...aws-amplify-react@1.0.2-unstable.0) (2018-07-19) - - +## [1.0.2-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1...aws-amplify-react@1.0.2-unstable.0) (2018-07-19) **Note:** Version bump only for package aws-amplify-react -## [1.0.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1-unstable.4...aws-amplify-react@1.0.1) (2018-07-18) - - +## [1.0.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1-unstable.4...aws-amplify-react@1.0.1) (2018-07-18) **Note:** Version bump only for package aws-amplify-react -## [1.0.1-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1-unstable.3...aws-amplify-react@1.0.1-unstable.4) (2018-07-18) - - +## [1.0.1-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1-unstable.3...aws-amplify-react@1.0.1-unstable.4) (2018-07-18) **Note:** Version bump only for package aws-amplify-react -## [1.0.1-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1-unstable.2...aws-amplify-react@1.0.1-unstable.3) (2018-07-18) - - +## [1.0.1-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1-unstable.2...aws-amplify-react@1.0.1-unstable.3) (2018-07-18) **Note:** Version bump only for package aws-amplify-react -## [1.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1-unstable.1...aws-amplify-react@1.0.1-unstable.2) (2018-07-18) - - +## [1.0.1-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1-unstable.1...aws-amplify-react@1.0.1-unstable.2) (2018-07-18) **Note:** Version bump only for package aws-amplify-react -## [1.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1...aws-amplify-react@1.0.1-unstable.1) (2018-07-18) - - +## [1.0.1-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1...aws-amplify-react@1.0.1-unstable.1) (2018-07-18) **Note:** Version bump only for package aws-amplify-react -## [1.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1...aws-amplify-react@1.0.1-unstable.0) (2018-07-18) - - +## [1.0.1-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@1.0.1...aws-amplify-react@1.0.1-unstable.0) (2018-07-18) **Note:** Version bump only for package aws-amplify-react -## [0.1.55-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.55-unstable.0...aws-amplify-react@0.1.55-unstable.1) (2018-07-03) - - +## [0.1.55-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.55-unstable.0...aws-amplify-react@0.1.55-unstable.1) (2018-07-03) **Note:** Version bump only for package aws-amplify-react -## [0.1.55-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54...aws-amplify-react@0.1.55-unstable.0) (2018-07-02) - - +## [0.1.55-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54...aws-amplify-react@0.1.55-unstable.0) (2018-07-02) **Note:** Version bump only for package aws-amplify-react -## [0.1.54](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.5...aws-amplify-react@0.1.54) (2018-06-29) - - +## [0.1.54](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.5...aws-amplify-react@0.1.54) (2018-06-29) **Note:** Version bump only for package aws-amplify-react -## [0.1.54-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.4...aws-amplify-react@0.1.54-unstable.5) (2018-06-29) - - +## [0.1.54-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.4...aws-amplify-react@0.1.54-unstable.5) (2018-06-29) **Note:** Version bump only for package aws-amplify-react -## [0.1.54-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.3...aws-amplify-react@0.1.54-unstable.4) (2018-06-29) - - +## [0.1.54-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.3...aws-amplify-react@0.1.54-unstable.4) (2018-06-29) **Note:** Version bump only for package aws-amplify-react -## [0.1.54-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.2...aws-amplify-react@0.1.54-unstable.3) (2018-06-28) - - +## [0.1.54-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.2...aws-amplify-react@0.1.54-unstable.3) (2018-06-28) **Note:** Version bump only for package aws-amplify-react -## [0.1.54-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.1...aws-amplify-react@0.1.54-unstable.2) (2018-06-27) - - +## [0.1.54-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.1...aws-amplify-react@0.1.54-unstable.2) (2018-06-27) **Note:** Version bump only for package aws-amplify-react -## [0.1.54-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.0...aws-amplify-react@0.1.54-unstable.1) (2018-06-27) - - +## [0.1.54-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.54-unstable.0...aws-amplify-react@0.1.54-unstable.1) (2018-06-27) **Note:** Version bump only for package aws-amplify-react -## [0.1.54-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.53-unstable.2...aws-amplify-react@0.1.54-unstable.0) (2018-06-27) +## [0.1.54-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.53-unstable.2...aws-amplify-react@0.1.54-unstable.0) (2018-06-27) ### Features -* **interactions:** Interactions UI components for react and react native ([#1105](https://github.com/aws/aws-amplify/issues/1105)) ([57de248](https://github.com/aws/aws-amplify/commit/57de248)) - - - +- **interactions:** Interactions UI components for react and react native ([#1105](https://github.com/aws/aws-amplify/issues/1105)) ([57de248](https://github.com/aws/aws-amplify/commit/57de248)) -## [0.1.53](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.53-unstable.2...aws-amplify-react@0.1.53) (2018-06-27) +## [0.1.53](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.53-unstable.2...aws-amplify-react@0.1.53) (2018-06-27) ### Features -* **interactions:** Interactions UI components for react and react native ([#1105](https://github.com/aws/aws-amplify/issues/1105)) ([57de248](https://github.com/aws/aws-amplify/commit/57de248)) - - - +- **interactions:** Interactions UI components for react and react native ([#1105](https://github.com/aws/aws-amplify/issues/1105)) ([57de248](https://github.com/aws/aws-amplify/commit/57de248)) -## [0.1.53-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.53-unstable.1...aws-amplify-react@0.1.53-unstable.2) (2018-06-26) +## [0.1.53-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.53-unstable.1...aws-amplify-react@0.1.53-unstable.2) (2018-06-26) ### Bug Fixes -* **integration tests:** CircleCI workflows and Cypress integration testing ([#1071](https://github.com/aws/aws-amplify/issues/1071)) ([bfa4776](https://github.com/aws/aws-amplify/commit/bfa4776)) - - - +- **integration tests:** CircleCI workflows and Cypress integration testing ([#1071](https://github.com/aws/aws-amplify/issues/1071)) ([bfa4776](https://github.com/aws/aws-amplify/commit/bfa4776)) -## [0.1.53-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.53-unstable.0...aws-amplify-react@0.1.53-unstable.1) (2018-06-22) - - +## [0.1.53-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.53-unstable.0...aws-amplify-react@0.1.53-unstable.1) (2018-06-22) **Note:** Version bump only for package aws-amplify-react -## [0.1.53-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.52...aws-amplify-react@0.1.53-unstable.0) (2018-06-22) - - +## [0.1.53-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.52...aws-amplify-react@0.1.53-unstable.0) (2018-06-22) **Note:** Version bump only for package aws-amplify-react -## [0.1.52](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.51-unstable.3...aws-amplify-react@0.1.52) (2018-06-21) - - +## [0.1.52](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.51-unstable.3...aws-amplify-react@0.1.52) (2018-06-21) **Note:** Version bump only for package aws-amplify-react -## [0.1.51](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.47...aws-amplify-react@0.1.51) (2018-06-20) - -## [0.1.51-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.51-unstable.2...aws-amplify-react@0.1.51-unstable.3) (2018-06-21) +## [0.1.51](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.47...aws-amplify-react@0.1.51) (2018-06-20) + +## [0.1.51-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.51-unstable.2...aws-amplify-react@0.1.51-unstable.3) (2018-06-21) **Note:** Version bump only for package aws-amplify-react -## [0.1.51-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.51-unstable.1...aws-amplify-react@0.1.51-unstable.2) (2018-06-21) - - +## [0.1.51-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.51-unstable.1...aws-amplify-react@0.1.51-unstable.2) (2018-06-21) **Note:** Version bump only for package aws-amplify-react -## [0.1.51-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.51-unstable.0...aws-amplify-react@0.1.51-unstable.1) (2018-06-20) - - +## [0.1.51-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.51-unstable.0...aws-amplify-react@0.1.51-unstable.1) (2018-06-20) **Note:** Version bump only for package aws-amplify-react -## [0.1.51-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.47...aws-amplify-react@0.1.51-unstable.0) (2018-06-20) +## [0.1.51-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.47...aws-amplify-react@0.1.51-unstable.0) (2018-06-20) ### Bug Fixes -* **pushnotification:** revert change in pr 952 ([b8d167c](https://github.com/aws/aws-amplify/commit/b8d167c)) -* **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) - - - +- **pushnotification:** revert change in pr 952 ([b8d167c](https://github.com/aws/aws-amplify/commit/b8d167c)) +- **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) -## [0.1.50](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.33...aws-amplify-react@0.1.50) (2018-06-04) +## [0.1.50](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.33...aws-amplify-react@0.1.50) (2018-06-04) ### Bug Fixes -* **pushnotification:** revert change in pr 952 ([b8d167c](https://github.com/aws/aws-amplify/commit/b8d167c)) -* **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) - - - +- **pushnotification:** revert change in pr 952 ([b8d167c](https://github.com/aws/aws-amplify/commit/b8d167c)) +- **pushnotification:** revert change in pr 952 ([257fc40](https://github.com/aws/aws-amplify/commit/257fc40)) -## [0.1.49](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48...aws-amplify-react@0.1.49) (2018-06-02) - -## [0.1.48-unstable.47](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.46...aws-amplify-react@0.1.48-unstable.47) (2018-06-19) +## [0.1.49](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48...aws-amplify-react@0.1.49) (2018-06-02) + +## [0.1.48-unstable.47](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.46...aws-amplify-react@0.1.48-unstable.47) (2018-06-19) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.46](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.45...aws-amplify-react@0.1.48-unstable.46) (2018-06-18) - - +## [0.1.48-unstable.46](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.45...aws-amplify-react@0.1.48-unstable.46) (2018-06-18) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.45](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.44...aws-amplify-react@0.1.48-unstable.45) (2018-06-18) - - +## [0.1.48-unstable.45](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.44...aws-amplify-react@0.1.48-unstable.45) (2018-06-18) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.44](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.43...aws-amplify-react@0.1.48-unstable.44) (2018-06-16) - - +## [0.1.48-unstable.44](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.43...aws-amplify-react@0.1.48-unstable.44) (2018-06-16) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.43](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.42...aws-amplify-react@0.1.48-unstable.43) (2018-06-13) - - +## [0.1.48-unstable.43](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.42...aws-amplify-react@0.1.48-unstable.43) (2018-06-13) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.42](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.41...aws-amplify-react@0.1.48-unstable.42) (2018-06-13) - - +## [0.1.48-unstable.42](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.41...aws-amplify-react@0.1.48-unstable.42) (2018-06-13) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.41](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.40...aws-amplify-react@0.1.48-unstable.41) (2018-06-12) - - +## [0.1.48-unstable.41](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.40...aws-amplify-react@0.1.48-unstable.41) (2018-06-12) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.40](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.39...aws-amplify-react@0.1.48-unstable.40) (2018-06-11) - - +## [0.1.48-unstable.40](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.39...aws-amplify-react@0.1.48-unstable.40) (2018-06-11) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.39](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.38...aws-amplify-react@0.1.48-unstable.39) (2018-06-08) - - +## [0.1.48-unstable.39](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.38...aws-amplify-react@0.1.48-unstable.39) (2018-06-08) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.38](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.37...aws-amplify-react@0.1.48-unstable.38) (2018-06-08) - - +## [0.1.48-unstable.38](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.37...aws-amplify-react@0.1.48-unstable.38) (2018-06-08) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.37](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.36...aws-amplify-react@0.1.48-unstable.37) (2018-06-07) - - +## [0.1.48-unstable.37](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.36...aws-amplify-react@0.1.48-unstable.37) (2018-06-07) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.36](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.35...aws-amplify-react@0.1.48-unstable.36) (2018-06-06) - - +## [0.1.48-unstable.36](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.35...aws-amplify-react@0.1.48-unstable.36) (2018-06-06) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.35](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.34...aws-amplify-react@0.1.48-unstable.35) (2018-06-05) - - +## [0.1.48-unstable.35](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.34...aws-amplify-react@0.1.48-unstable.35) (2018-06-05) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.34](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.33...aws-amplify-react@0.1.48-unstable.34) (2018-06-04) - - +## [0.1.48-unstable.34](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.33...aws-amplify-react@0.1.48-unstable.34) (2018-06-04) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.33](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.32...aws-amplify-react@0.1.48-unstable.33) (2018-06-04) - - +## [0.1.48-unstable.33](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.32...aws-amplify-react@0.1.48-unstable.33) (2018-06-04) **Note:** Version bump only for package aws-amplify-react -## [0.1.48](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.30...aws-amplify-react@0.1.48) (2018-06-01) - -## [0.1.48-unstable.32](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.31...aws-amplify-react@0.1.48-unstable.32) (2018-06-04) +## [0.1.48](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.30...aws-amplify-react@0.1.48) (2018-06-01) + +## [0.1.48-unstable.32](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.31...aws-amplify-react@0.1.48-unstable.32) (2018-06-04) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.31](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.30...aws-amplify-react@0.1.48-unstable.31) (2018-06-02) - - +## [0.1.48-unstable.31](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.30...aws-amplify-react@0.1.48-unstable.31) (2018-06-02) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.30](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.29...aws-amplify-react@0.1.48-unstable.30) (2018-06-01) - - +## [0.1.48-unstable.30](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.29...aws-amplify-react@0.1.48-unstable.30) (2018-06-01) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.29](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.28...aws-amplify-react@0.1.48-unstable.29) (2018-06-01) - - +## [0.1.48-unstable.29](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.28...aws-amplify-react@0.1.48-unstable.29) (2018-06-01) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.28](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.27...aws-amplify-react@0.1.48-unstable.28) (2018-06-01) - - +## [0.1.48-unstable.28](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.27...aws-amplify-react@0.1.48-unstable.28) (2018-06-01) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.27](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.26...aws-amplify-react@0.1.48-unstable.27) (2018-05-31) - - +## [0.1.48-unstable.27](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.26...aws-amplify-react@0.1.48-unstable.27) (2018-05-31) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.26](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.23...aws-amplify-react@0.1.48-unstable.26) (2018-05-31) - - +## [0.1.48-unstable.26](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.23...aws-amplify-react@0.1.48-unstable.26) (2018-05-31) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.23](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.22...aws-amplify-react@0.1.48-unstable.23) (2018-05-31) - - +## [0.1.48-unstable.23](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.22...aws-amplify-react@0.1.48-unstable.23) (2018-05-31) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.22](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.21...aws-amplify-react@0.1.48-unstable.22) (2018-05-31) - - +## [0.1.48-unstable.22](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.21...aws-amplify-react@0.1.48-unstable.22) (2018-05-31) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.21](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.20...aws-amplify-react@0.1.48-unstable.21) (2018-05-30) - - +## [0.1.48-unstable.21](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.20...aws-amplify-react@0.1.48-unstable.21) (2018-05-30) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.20](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.19...aws-amplify-react@0.1.48-unstable.20) (2018-05-29) - - +## [0.1.48-unstable.20](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.19...aws-amplify-react@0.1.48-unstable.20) (2018-05-29) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.19](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.18...aws-amplify-react@0.1.48-unstable.19) (2018-05-29) - - +## [0.1.48-unstable.19](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.18...aws-amplify-react@0.1.48-unstable.19) (2018-05-29) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.18](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.17...aws-amplify-react@0.1.48-unstable.18) (2018-05-29) - - +## [0.1.48-unstable.18](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.17...aws-amplify-react@0.1.48-unstable.18) (2018-05-29) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.16...aws-amplify-react@0.1.48-unstable.17) (2018-05-24) - - +## [0.1.48-unstable.17](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.16...aws-amplify-react@0.1.48-unstable.17) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.15...aws-amplify-react@0.1.48-unstable.16) (2018-05-24) - - +## [0.1.48-unstable.16](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.15...aws-amplify-react@0.1.48-unstable.16) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.14...aws-amplify-react@0.1.48-unstable.15) (2018-05-24) - - +## [0.1.48-unstable.15](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.14...aws-amplify-react@0.1.48-unstable.15) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.13...aws-amplify-react@0.1.48-unstable.14) (2018-05-24) - - +## [0.1.48-unstable.14](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.13...aws-amplify-react@0.1.48-unstable.14) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.12...aws-amplify-react@0.1.48-unstable.13) (2018-05-24) - - +## [0.1.48-unstable.13](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.12...aws-amplify-react@0.1.48-unstable.13) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.11...aws-amplify-react@0.1.48-unstable.12) (2018-05-24) - - +## [0.1.48-unstable.12](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.11...aws-amplify-react@0.1.48-unstable.12) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.10...aws-amplify-react@0.1.48-unstable.11) (2018-05-24) - - +## [0.1.48-unstable.11](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.10...aws-amplify-react@0.1.48-unstable.11) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.47...aws-amplify-react@0.1.48-unstable.10) (2018-05-24) - - +## [0.1.48-unstable.10](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.47...aws-amplify-react@0.1.48-unstable.10) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.8...aws-amplify-react@0.1.48-unstable.9) (2018-05-24) - - +## [0.1.48-unstable.9](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.8...aws-amplify-react@0.1.48-unstable.9) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.7...aws-amplify-react@0.1.48-unstable.8) (2018-05-24) - - +## [0.1.48-unstable.8](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.7...aws-amplify-react@0.1.48-unstable.8) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.6...aws-amplify-react@0.1.48-unstable.7) (2018-05-24) - - +## [0.1.48-unstable.7](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.6...aws-amplify-react@0.1.48-unstable.7) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.5...aws-amplify-react@0.1.48-unstable.6) (2018-05-24) - - +## [0.1.48-unstable.6](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.5...aws-amplify-react@0.1.48-unstable.6) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.4...aws-amplify-react@0.1.48-unstable.5) (2018-05-24) - - +## [0.1.48-unstable.5](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.4...aws-amplify-react@0.1.48-unstable.5) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.3...aws-amplify-react@0.1.48-unstable.4) (2018-05-24) - - +## [0.1.48-unstable.4](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.3...aws-amplify-react@0.1.48-unstable.4) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.2...aws-amplify-react@0.1.48-unstable.3) (2018-05-24) - - +## [0.1.48-unstable.3](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.2...aws-amplify-react@0.1.48-unstable.3) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.1...aws-amplify-react@0.1.48-unstable.2) (2018-05-24) - - +## [0.1.48-unstable.2](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.1...aws-amplify-react@0.1.48-unstable.2) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.0...aws-amplify-react@0.1.48-unstable.1) (2018-05-24) - - +## [0.1.48-unstable.1](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.48-unstable.0...aws-amplify-react@0.1.48-unstable.1) (2018-05-24) **Note:** Version bump only for package aws-amplify-react -## [0.1.48-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.47...aws-amplify-react@0.1.48-unstable.0) (2018-05-23) - - +## [0.1.48-unstable.0](https://github.com/aws/aws-amplify/compare/aws-amplify-react@0.1.47...aws-amplify-react@0.1.48-unstable.0) (2018-05-23) **Note:** Version bump only for package aws-amplify-react diff --git a/packages/aws-amplify-react/__tests__/Amplify-UI/Amplify-UI-Components-React-test.js b/packages/aws-amplify-react/__tests__/Amplify-UI/Amplify-UI-Components-React-test.js index a2256305731..18630a9f977 100644 --- a/packages/aws-amplify-react/__tests__/Amplify-UI/Amplify-UI-Components-React-test.js +++ b/packages/aws-amplify-react/__tests__/Amplify-UI/Amplify-UI-Components-React-test.js @@ -2,219 +2,201 @@ import * as React from 'react'; import * as UI from '../../src/Amplify-UI/Amplify-UI-Components-React'; describe('AmplifyUi test', () => { - test('render Container correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render FormContainer correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SectionHeader correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SectionHeaderContent correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SectionFooter correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SectionFooterPrimaryContent correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SectionFooterSecondaryContent correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SectionBody correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render Strike correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render StrikeContent correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render FormRow correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render Radio correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render RadioRow correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render InputRow correctly', () => { - - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render Input correctly', () => { - - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SelectInput correctly', () => { - - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - - // test('render CheckboxRow correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render MessageRow correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render ButtonRow correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render Link correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - - - - - - - // test('render ErrorSection correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - - - - - - - // test('render ActionRow correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - - - // test('render Checkbox correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render Button correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render ButtonContent correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render SignInButton correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render Label correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render Space correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render NavBar correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render Nav correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render NavRight correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render NavItem correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); - - // test('render NavButton correctly', () => { - // const wrapper = shallow(); - // wrapper.setProps({ theme: 'theme' }); - // expect(wrapper).toMatchSnapshot(); - // }); + test('render Container correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render FormContainer correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SectionHeader correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SectionHeaderContent correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SectionFooter correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SectionFooterPrimaryContent correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SectionFooterSecondaryContent correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SectionBody correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render Strike correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render StrikeContent correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render FormRow correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render Radio correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render RadioRow correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render InputRow correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render Input correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SelectInput correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + // test('render CheckboxRow correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render MessageRow correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render ButtonRow correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render Link correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render ErrorSection correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render ActionRow correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render Checkbox correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render Button correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render ButtonContent correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render SignInButton correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render Label correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render Space correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render NavBar correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render Nav correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render NavRight correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render NavItem correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); + + // test('render NavButton correctly', () => { + // const wrapper = shallow(); + // wrapper.setProps({ theme: 'theme' }); + // expect(wrapper).toMatchSnapshot(); + // }); }); diff --git a/packages/aws-amplify-react/__tests__/AmplifyMessageMap-test.js b/packages/aws-amplify-react/__tests__/AmplifyMessageMap-test.js index df0da884fe3..80f5aa89395 100644 --- a/packages/aws-amplify-react/__tests__/AmplifyMessageMap-test.js +++ b/packages/aws-amplify-react/__tests__/AmplifyMessageMap-test.js @@ -1,32 +1,36 @@ -import { MapEntries, default as AmplifyMessageMap} from '../src/AmplifyMessageMap'; +import { + MapEntries, + default as AmplifyMessageMap, +} from '../src/AmplifyMessageMap'; test('MapEntries', () => { - expect(MapEntries).toEqual([ - ["User does not exist", /user.*not.*exist/i], - ["User already exists", /user.*already.*exist/i], - ["Incorrect username or password", /incorrect.*username.*password/i], - ["Invalid password format", /validation.*password/i], - [ - "Invalid phone number format", - /invalid.*phone/i, - "Invalid phone number format. Please use a phone number format of +12345678900" - ] - ]); -}); + expect(MapEntries).toEqual([ + ['User does not exist', /user.*not.*exist/i], + ['User already exists', /user.*already.*exist/i], + ['Incorrect username or password', /incorrect.*username.*password/i], + ['Invalid password format', /validation.*password/i], + [ + 'Invalid phone number format', + /invalid.*phone/i, + 'Invalid phone number format. Please use a phone number format of +12345678900', + ], + ]); +}); test('AmplifyMessageMap error message', () => { - expect(AmplifyMessageMap('user not exist')).toBe('User does not exist'); + expect(AmplifyMessageMap('user not exist')).toBe('User does not exist'); }); test('AmplifyMessageMap happy case', () => { - expect(AmplifyMessageMap('')).toBe(''); + expect(AmplifyMessageMap('')).toBe(''); }); test('AmplifyMessageMap no match', () => { - expect(AmplifyMessageMap('abc')).toBe('abc'); + expect(AmplifyMessageMap('abc')).toBe('abc'); }); test('AmplifyMessageMap return message instead of i18n token if message exists', () => { - expect(AmplifyMessageMap('invalid phone')) - .toBe('Invalid phone number format. Please use a phone number format of +12345678900'); + expect(AmplifyMessageMap('invalid phone')).toBe( + 'Invalid phone number format. Please use a phone number format of +12345678900' + ); }); diff --git a/packages/aws-amplify-react/__tests__/AmplifyUI-test.js b/packages/aws-amplify-react/__tests__/AmplifyUI-test.js index 5f633dff440..58bd8c0f8f6 100644 --- a/packages/aws-amplify-react/__tests__/AmplifyUI-test.js +++ b/packages/aws-amplify-react/__tests__/AmplifyUI-test.js @@ -2,177 +2,177 @@ import * as React from 'react'; import * as UI from '../src/AmplifyUI'; describe('AmplifyUi test', () => { - test('render InputRow correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render RadioRow correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render CheckboxRow correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render MessageRow correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render ButtonRow correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render Link correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render Container correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render FormContainer correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render FormSection correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render ErrorSection correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SectionHeader correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SectionHeaderContent correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SectionFooter correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SectionFooterContent correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SectionBody correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render ActionRow correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render FormRow correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render Radio correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render Checkbox correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render Button correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render ButtonContent correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render SignInButton correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render Label correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render Space correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render NavBar correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render Nav correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render NavRight correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render NavItem correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render NavButton correctly', () => { - const wrapper = shallow(); - wrapper.setProps({ theme: 'theme' }); - expect(wrapper).toMatchSnapshot(); - }); + test('render InputRow correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render RadioRow correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render CheckboxRow correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render MessageRow correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render ButtonRow correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render Link correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render Container correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render FormContainer correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render FormSection correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render ErrorSection correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SectionHeader correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SectionHeaderContent correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SectionFooter correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SectionFooterContent correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SectionBody correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render ActionRow correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render FormRow correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render Radio correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render Checkbox correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render Button correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render ButtonContent correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render SignInButton correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render Label correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render Space correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render NavBar correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render Nav correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render NavRight correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render NavItem correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render NavButton correctly', () => { + const wrapper = shallow(); + wrapper.setProps({ theme: 'theme' }); + expect(wrapper).toMatchSnapshot(); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Analytics/trackLifecycle-test.js b/packages/aws-amplify-react/__tests__/Analytics/trackLifecycle-test.js index ded1a3ac141..df3b92e26b3 100644 --- a/packages/aws-amplify-react/__tests__/Analytics/trackLifecycle-test.js +++ b/packages/aws-amplify-react/__tests__/Analytics/trackLifecycle-test.js @@ -4,68 +4,68 @@ import Analytics from '@aws-amplify/analytics'; import { trackLifecycle } from '../../src/Analytics/trackLifecycle'; describe('trackLifecycle test', () => { - test('render correctly', () => { - const spyon = jest.spyOn(Analytics, 'record'); - const MockComp = class extends Component { - render() { - return
; - } - }; - const CompWithAuth = trackLifecycle(MockComp, 'trackername'); - const wrapper = shallow(); + test('render correctly', () => { + const spyon = jest.spyOn(Analytics, 'record'); + const MockComp = class extends Component { + render() { + return
; + } + }; + const CompWithAuth = trackLifecycle(MockComp, 'trackername'); + const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - expect(spyon).toBeCalled(); + expect(wrapper).toMatchSnapshot(); + expect(spyon).toBeCalled(); - spyon.mockClear(); - }); + spyon.mockClear(); + }); - test('track when mounting', () => { - const spyon = jest.spyOn(Analytics, 'record'); - const MockComp = class extends Component { - render() { - return
; - } - }; - const CompWithAuth = trackLifecycle(MockComp, 'trackername'); - const wrapper = mount(); - - expect(spyon.mock.calls.length).toBe(2); + test('track when mounting', () => { + const spyon = jest.spyOn(Analytics, 'record'); + const MockComp = class extends Component { + render() { + return
; + } + }; + const CompWithAuth = trackLifecycle(MockComp, 'trackername'); + const wrapper = mount(); - spyon.mockClear(); - wrapper.unmount(); - }); + expect(spyon.mock.calls.length).toBe(2); - test('track when unmounting', () => { - const spyon = jest.spyOn(Analytics, 'record'); - const MockComp = class extends Component { - render() { - return
; - } - }; - const CompWithAuth = trackLifecycle(MockComp, 'trackername'); - const wrapper = shallow(); - - wrapper.unmount(); - expect(spyon.mock.calls.length).toBe(2); + spyon.mockClear(); + wrapper.unmount(); + }); - spyon.mockClear(); - }); + test('track when unmounting', () => { + const spyon = jest.spyOn(Analytics, 'record'); + const MockComp = class extends Component { + render() { + return
; + } + }; + const CompWithAuth = trackLifecycle(MockComp, 'trackername'); + const wrapper = shallow(); - test('track when updating', () => { - const spyon = jest.spyOn(Analytics, 'record'); - const MockComp = class extends Component { - render() { - return
; - } - }; - const CompWithAuth = trackLifecycle(MockComp, 'trackername'); - const wrapper = shallow(); + wrapper.unmount(); + expect(spyon.mock.calls.length).toBe(2); - wrapper.update(); - - expect(spyon.mock.calls.length).toBe(2); + spyon.mockClear(); + }); - spyon.mockClear(); - }); + test('track when updating', () => { + const spyon = jest.spyOn(Analytics, 'record'); + const MockComp = class extends Component { + render() { + return
; + } + }; + const CompWithAuth = trackLifecycle(MockComp, 'trackername'); + const wrapper = shallow(); + + wrapper.update(); + + expect(spyon.mock.calls.length).toBe(2); + + spyon.mockClear(); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/AuthPiece-test.js b/packages/aws-amplify-react/__tests__/Auth/AuthPiece-test.js index 70d2a9c084a..c2e899e4909 100644 --- a/packages/aws-amplify-react/__tests__/Auth/AuthPiece-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/AuthPiece-test.js @@ -2,197 +2,205 @@ import AuthPiece from '../../src/Auth/AuthPiece'; import * as React from 'react'; class TestPiece extends AuthPiece { - constructor(props) { - super(props); - } - render() { - return ( -
- ); - } + constructor(props) { + super(props); + } + render() { + return
; + } } describe('AuthPiece test', () => { - describe('usernameFromAuthData test', () => { - test('happy case with string type authdata', () => { - const props = { - authData: 'username' - }; - const wrapper = shallow(); - const testPiece = wrapper.instance(); - wrapper.setProps(props); - - expect(testPiece.usernameFromAuthData()).toBe('username'); - }); - - test('happy case with object type authdata', () => { - const props = { - authData: { - username: 'username' - } - }; - const props2 = { - authData: { - user: { - username: 'username' - } - } - }; - const wrapper = shallow(); - const testPiece = wrapper.instance(); - wrapper.setProps(props); - - expect(testPiece.usernameFromAuthData()).toBe('username'); - - wrapper.setProps(props2); - - expect(testPiece.usernameFromAuthData()).toBe('username'); - }); - - test('no authData', () => { - const wrapper = shallow(); - const testPiece = wrapper.instance(); - - expect(testPiece.usernameFromAuthData()).toBe(''); - }); - }); - - describe('errorMessage test', () => { - test('happy case', () => { - const wrapper = shallow(); - const testPiece = wrapper.instance(); - - expect(testPiece.errorMessage('err')).toBe('err'); - }); - - test('happy case with object param', () => { - const wrapper = shallow(); - const testPiece = wrapper.instance(); - - expect(testPiece.errorMessage({message:'err'})).toBe('err'); - expect(testPiece.errorMessage({something: 'something'})).toBe(JSON.stringify({something: 'something'})); - }); - }); - - describe('triggerAuthEvent test', () => { - test('happy case', () => { - const mockFn = jest.fn(); - const props = { - authState: 'state', - onAuthEvent: mockFn - }; - const wrapper = shallow(); - const testPiece = wrapper.instance(); - wrapper.setProps(props); - - testPiece.triggerAuthEvent('event'); - - expect(mockFn).toBeCalledWith('state', 'event'); - }); - - test('no onAuthEvent', () => { - const props = { - authState: 'state' - }; - const wrapper = shallow(); - const testPiece = wrapper.instance(); - wrapper.setProps(props); - - testPiece.triggerAuthEvent('event'); - }); - }); - - describe('changeState test', () => { - test('happy case', () => { - const spyon = jest.spyOn(AuthPiece.prototype, 'triggerAuthEvent').mockImplementationOnce(() => { - return; - }); - - const mockFn = jest.fn(); - const props = { - onStateChange: mockFn - }; - const wrapper = shallow(); - const testPiece = wrapper.instance(); - wrapper.setProps(props); - - testPiece.changeState('state', 'data'); - - expect(mockFn).toBeCalledWith('state', 'data'); - expect(spyon).toBeCalledWith({"data": "state", "type": "stateChange"}); - - spyon.mockClear(); - }); - - test('happy case', () => { - const spyon = jest.spyOn(AuthPiece.prototype, 'triggerAuthEvent').mockImplementationOnce(() => { - return; - }); - const wrapper = shallow(); - const testPiece = wrapper.instance(); - - testPiece.changeState('state', 'data'); - expect(spyon).toBeCalledWith({"data": "state", "type": "stateChange"}); - - spyon.mockClear(); - }); - }); - - describe('error test', () => { - test('happy case', () => { - const spyon = jest.spyOn(AuthPiece.prototype, 'triggerAuthEvent').mockImplementationOnce(() => { - return; - }); - - const spyon2 = jest.spyOn(AuthPiece.prototype, 'errorMessage').mockImplementationOnce(() => { - return 'errMessage'; - }); - - const wrapper = shallow(); - const testPiece = wrapper.instance(); - - testPiece.error('err'); - - expect(spyon).toBeCalledWith({data: 'errMessage', type: 'error'}); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); - - describe('handleInputChange test', () => { - test('happy case', () => { - const event = { - target: { - name: 'name', - value: 'value', - type: 'radio', - checked: true - } - }; - const wrapper = shallow(); - const testPiece = wrapper.instance(); - - testPiece.handleInputChange(event); - - expect(testPiece.inputs).toEqual( {"checkedValue": "value", "name": true}); - }); - - test('happy case without checke_type', () => { - const event = { - target: { - name: 'name', - value: 'value', - type: 'other_type', - checked: '' - } - }; - const wrapper = shallow(); - const testPiece = wrapper.instance(); - - testPiece.handleInputChange(event); - - expect(testPiece.inputs).toEqual({"checkedValue": null, "name": "value"}); - }); - }); + describe('usernameFromAuthData test', () => { + test('happy case with string type authdata', () => { + const props = { + authData: 'username', + }; + const wrapper = shallow(); + const testPiece = wrapper.instance(); + wrapper.setProps(props); + + expect(testPiece.usernameFromAuthData()).toBe('username'); + }); + + test('happy case with object type authdata', () => { + const props = { + authData: { + username: 'username', + }, + }; + const props2 = { + authData: { + user: { + username: 'username', + }, + }, + }; + const wrapper = shallow(); + const testPiece = wrapper.instance(); + wrapper.setProps(props); + + expect(testPiece.usernameFromAuthData()).toBe('username'); + + wrapper.setProps(props2); + + expect(testPiece.usernameFromAuthData()).toBe('username'); + }); + + test('no authData', () => { + const wrapper = shallow(); + const testPiece = wrapper.instance(); + + expect(testPiece.usernameFromAuthData()).toBe(''); + }); + }); + + describe('errorMessage test', () => { + test('happy case', () => { + const wrapper = shallow(); + const testPiece = wrapper.instance(); + + expect(testPiece.errorMessage('err')).toBe('err'); + }); + + test('happy case with object param', () => { + const wrapper = shallow(); + const testPiece = wrapper.instance(); + + expect(testPiece.errorMessage({ message: 'err' })).toBe('err'); + expect(testPiece.errorMessage({ something: 'something' })).toBe( + JSON.stringify({ something: 'something' }) + ); + }); + }); + + describe('triggerAuthEvent test', () => { + test('happy case', () => { + const mockFn = jest.fn(); + const props = { + authState: 'state', + onAuthEvent: mockFn, + }; + const wrapper = shallow(); + const testPiece = wrapper.instance(); + wrapper.setProps(props); + + testPiece.triggerAuthEvent('event'); + + expect(mockFn).toBeCalledWith('state', 'event'); + }); + + test('no onAuthEvent', () => { + const props = { + authState: 'state', + }; + const wrapper = shallow(); + const testPiece = wrapper.instance(); + wrapper.setProps(props); + + testPiece.triggerAuthEvent('event'); + }); + }); + + describe('changeState test', () => { + test('happy case', () => { + const spyon = jest + .spyOn(AuthPiece.prototype, 'triggerAuthEvent') + .mockImplementationOnce(() => { + return; + }); + + const mockFn = jest.fn(); + const props = { + onStateChange: mockFn, + }; + const wrapper = shallow(); + const testPiece = wrapper.instance(); + wrapper.setProps(props); + + testPiece.changeState('state', 'data'); + + expect(mockFn).toBeCalledWith('state', 'data'); + expect(spyon).toBeCalledWith({ data: 'state', type: 'stateChange' }); + + spyon.mockClear(); + }); + + test('happy case', () => { + const spyon = jest + .spyOn(AuthPiece.prototype, 'triggerAuthEvent') + .mockImplementationOnce(() => { + return; + }); + const wrapper = shallow(); + const testPiece = wrapper.instance(); + + testPiece.changeState('state', 'data'); + expect(spyon).toBeCalledWith({ data: 'state', type: 'stateChange' }); + + spyon.mockClear(); + }); + }); + + describe('error test', () => { + test('happy case', () => { + const spyon = jest + .spyOn(AuthPiece.prototype, 'triggerAuthEvent') + .mockImplementationOnce(() => { + return; + }); + + const spyon2 = jest + .spyOn(AuthPiece.prototype, 'errorMessage') + .mockImplementationOnce(() => { + return 'errMessage'; + }); + + const wrapper = shallow(); + const testPiece = wrapper.instance(); + + testPiece.error('err'); + + expect(spyon).toBeCalledWith({ data: 'errMessage', type: 'error' }); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); + + describe('handleInputChange test', () => { + test('happy case', () => { + const event = { + target: { + name: 'name', + value: 'value', + type: 'radio', + checked: true, + }, + }; + const wrapper = shallow(); + const testPiece = wrapper.instance(); + + testPiece.handleInputChange(event); + + expect(testPiece.inputs).toEqual({ checkedValue: 'value', name: true }); + }); + + test('happy case without checke_type', () => { + const event = { + target: { + name: 'name', + value: 'value', + type: 'other_type', + checked: '', + }, + }; + const wrapper = shallow(); + const testPiece = wrapper.instance(); + + testPiece.handleInputChange(event); + + expect(testPiece.inputs).toEqual({ checkedValue: null, name: 'value' }); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/Authenticator-test.js b/packages/aws-amplify-react/__tests__/Auth/Authenticator-test.js index 4746f03473c..44eb75807c1 100644 --- a/packages/aws-amplify-react/__tests__/Auth/Authenticator-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/Authenticator-test.js @@ -2,164 +2,187 @@ import Auth from '@aws-amplify/auth'; import * as React from 'react'; import Authenticator, { EmptyContainer } from '../../src/Auth/Authenticator'; import SignIn from '../../src/Auth/SignIn'; -import AmplifyTheme from '../../src/AmplifyTheme'; -import { Button, InputRow, Container } from '../../src/Amplify-UI/Amplify-UI-Components-React'; +import AmplifyTheme from '../../src/AmplifyTheme'; +import { + Button, + InputRow, + Container, +} from '../../src/Amplify-UI/Amplify-UI-Components-React'; const waitForResolve = Promise.resolve(); describe('Authenticator', () => { - beforeAll(() => { - const localStorageMock = { - getItem: jest.fn(), - setItem: jest.fn(), - removeItem: jest.fn(), - clear: jest.fn() - }; - global.localStorage = localStorageMock; - }) - afterAll(() => { - jest.resetAllMocks(); - }) - describe('normal case', () => { - - test('render if no error', () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: 'signIn', - theme: AmplifyTheme - }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render with hidedefault', () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: 'signIn', - theme: AmplifyTheme - }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render if no error with children', () => { - const wrapper = shallow(
); - wrapper.setProps({ - authState: 'signIn', - theme: AmplifyTheme - }); - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe.skip('handleStateChange test', () => { - test('when user sign in and need confirmation', async () => { - const wrapper = shallow(); - - const spyon = jest.spyOn(Auth, 'signIn') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res({ - challengeName: 'SMS_MFA' - }); - }); - }); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - const event_password = { - target: { - name: 'password', - value: 'abc' - } - }; - - const signInWrapper = wrapper.find(SignIn).dive(); - signInWrapper.find(InputRow).at(0).simulate('change', event_username); - signInWrapper.find(InputRow).at(1).simulate('change', event_password); - await signInWrapper.find(Button).simulate('click'); - - expect(wrapper.state()).toEqual({ - "auth": "confirmSignIn", - "authData": {"challengeName": "SMS_MFA"}, - "error": null - }); - - spyon.mockClear(); - }); - }); - - describe.skip('handleAuthEvent test', () => { - test('when user sign in failed', async () => { - const wrapper = shallow(); - - const spyon = jest.spyOn(Auth, 'signIn') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - const event_password = { - target: { - name: 'password', - value: 'abc' - } - }; - - const signInWrapper = wrapper.find(SignIn).dive(); - signInWrapper.find(Input).at(0).simulate('change', event_username); - signInWrapper.find(Input).at(1).simulate('change', event_password); - await signInWrapper.find(Button).simulate('click'); - - expect(wrapper.state()).toEqual({ - "auth": "signIn" - }); - - spyon.mockClear(); - }); - }); - - describe('checkUser test', () => { - test('happy case', async () => { - const wrapper = shallow(); - const authenticator = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'currentAuthenticatedUser').mockImplementationOnce(() => { - return Promise.resolve('user'); - }); - - await authenticator.checkUser(); - - expect(spyon).toBeCalled(); - }); - }); - - describe('container component', () => { - test("use provided Container component if this.props.container is truthy", () => { - const CustomContainer = ({ children }) => { - return
{children}
; - }; - const wrapper = mount(); - expect(wrapper.childAt(0).type()).toBe(CustomContainer); - }); - - test("use AWS Amplify UI Container if this.props.container is undefined", () => { - const wrapper = mount(); - expect(wrapper.childAt(0).type()).toBe(Container); - }); - - test("use EmptyContainer if this.props.container is falsey", () => { - const wrapper = mount(); - expect(wrapper.childAt(0).type()).toBe(EmptyContainer); - }); - }); + beforeAll(() => { + const localStorageMock = { + getItem: jest.fn(), + setItem: jest.fn(), + removeItem: jest.fn(), + clear: jest.fn(), + }; + global.localStorage = localStorageMock; + }); + afterAll(() => { + jest.resetAllMocks(); + }); + describe('normal case', () => { + test('render if no error', () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: 'signIn', + theme: AmplifyTheme, + }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render with hidedefault', () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: 'signIn', + theme: AmplifyTheme, + }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render if no error with children', () => { + const wrapper = shallow( + +
+
+ ); + wrapper.setProps({ + authState: 'signIn', + theme: AmplifyTheme, + }); + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe.skip('handleStateChange test', () => { + test('when user sign in and need confirmation', async () => { + const wrapper = shallow(); + + const spyon = jest + .spyOn(Auth, 'signIn') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res({ + challengeName: 'SMS_MFA', + }); + }); + }); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + const signInWrapper = wrapper.find(SignIn).dive(); + signInWrapper + .find(InputRow) + .at(0) + .simulate('change', event_username); + signInWrapper + .find(InputRow) + .at(1) + .simulate('change', event_password); + await signInWrapper.find(Button).simulate('click'); + + expect(wrapper.state()).toEqual({ + auth: 'confirmSignIn', + authData: { challengeName: 'SMS_MFA' }, + error: null, + }); + + spyon.mockClear(); + }); + }); + + describe.skip('handleAuthEvent test', () => { + test('when user sign in failed', async () => { + const wrapper = shallow(); + + const spyon = jest + .spyOn(Auth, 'signIn') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + const signInWrapper = wrapper.find(SignIn).dive(); + signInWrapper + .find(Input) + .at(0) + .simulate('change', event_username); + signInWrapper + .find(Input) + .at(1) + .simulate('change', event_password); + await signInWrapper.find(Button).simulate('click'); + + expect(wrapper.state()).toEqual({ + auth: 'signIn', + }); + + spyon.mockClear(); + }); + }); + + describe('checkUser test', () => { + test('happy case', async () => { + const wrapper = shallow(); + const authenticator = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'currentAuthenticatedUser') + .mockImplementationOnce(() => { + return Promise.resolve('user'); + }); + + await authenticator.checkUser(); + + expect(spyon).toBeCalled(); + }); + }); + + describe('container component', () => { + test('use provided Container component if this.props.container is truthy', () => { + const CustomContainer = ({ children }) => { + return
{children}
; + }; + const wrapper = mount(); + expect(wrapper.childAt(0).type()).toBe(CustomContainer); + }); + + test('use AWS Amplify UI Container if this.props.container is undefined', () => { + const wrapper = mount(); + expect(wrapper.childAt(0).type()).toBe(Container); + }); + + test('use EmptyContainer if this.props.container is falsey', () => { + const wrapper = mount(); + expect(wrapper.childAt(0).type()).toBe(EmptyContainer); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/ConfirmSignIn-test.js b/packages/aws-amplify-react/__tests__/Auth/ConfirmSignIn-test.js index a3d328f3700..f476d3fd315 100644 --- a/packages/aws-amplify-react/__tests__/Auth/ConfirmSignIn-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/ConfirmSignIn-test.js @@ -3,191 +3,213 @@ import ConfirmSignIn from '../../src/Auth/ConfirmSignIn'; import * as React from 'react'; import AmplifyTheme from '../../src/AmplifyTheme'; import AuthPiece from '../../src/Auth/AuthPiece'; -import { Header, Footer, Input, Button, Link } from '../../src/Amplify-UI/Amplify-UI-Components-React'; +import { + Header, + Footer, + Input, + Button, + Link, +} from '../../src/Amplify-UI/Amplify-UI-Components-React'; -const acceptedStates = [ - 'confirmSignIn' -]; +const acceptedStates = ['confirmSignIn']; const deniedStates = [ - 'signIn', - 'signedUp', - 'signedOut', - 'signUp', - 'signedIn', - 'confirmSignUp', - 'forgotPassword', - 'verifyContact' + 'signIn', + 'signedUp', + 'signedOut', + 'signUp', + 'signedIn', + 'confirmSignUp', + 'forgotPassword', + 'verifyContact', ]; const fakeEvent = { - preventDefault: jest.fn() + preventDefault: jest.fn(), }; describe('ConfirmSignIn', () => { - describe('render test', () => { - test('render correctly with Props confirmSignIn', () => { - const wrapper = shallow(); - for (let i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('render corrently with other authstate', () => { - const wrapper = shallow(); - - for (let i = 0; i < deniedStates.length; i += 1){ - wrapper.setProps({ - authState: deniedStates[i], - theme: AmplifyTheme - }); - - expect(wrapper).toMatchSnapshot(); - } - }); - - test('hidden if hide include confirmSignIn', () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: acceptedStates[0], - hide: [ConfirmSignIn] - }); - expect(wrapper).toMatchSnapshot(); - }); - - }); - - describe('confirm test', () => { - test('user with challengeName SOFTWARE_TOKEN_MFA', async () => { - const wrapper = shallow(); - - const spyon = jest.spyOn(Auth, 'confirmSignIn').mockImplementationOnce(() => { - return Promise.resolve(); - }); - - wrapper.setProps({ - authState: acceptedStates[0], - theme: AmplifyTheme, - authData: { - user: { - challengeName: 'SOFTWARE_TOKEN_MFA' - } - } - }); - - const confirmSignIn = wrapper.instance(); - - await confirmSignIn.confirm(); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - }); - - describe('normal case', () => { - test('simulate clicking confirm button', async () => { - const spyon = jest.spyOn(Auth, 'confirmSignIn') - .mockImplementation((user, code) => { - return new Promise((res, rej) => { - res(); - }); - }); - - const wrapper = shallow(); - const spyon2 = jest.spyOn(wrapper.instance(), 'checkContact'); - wrapper.setProps({ - authState: acceptedStates[0], - theme: AmplifyTheme, - authData: 'user' - }); - - const event_code = { - target: { - name: 'code', - value: '123456' - } - }; - - wrapper.find(Input).at(0).simulate('change', event_code); - wrapper.find('form').at(0).simulate('submit', fakeEvent); - - await Promise.resolve(); - - expect.assertions(3); - expect(spyon.mock.calls[0][0]).toBe('user'); - expect(spyon.mock.calls[0][1]).toBe('123456'); - expect(spyon2).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('back to sign in', () => { - const wrapper = shallow(); - const spyon2 = jest.spyOn(wrapper.instance(), 'changeState'); - wrapper.setProps({ - authState: acceptedStates[0], - theme: AmplifyTheme, - authData: 'user' - }); - - wrapper.find(Link).at(0).simulate('click'); - expect(spyon2).toBeCalledWith('signIn'); - - spyon2.mockClear(); - }); - }); - - describe('checkContact test', () => { - test('contact verified', async () => { - const wrapper = shallow(); - const confirmSignIn = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'verifiedContact').mockImplementationOnce(() => { - return Promise.resolve({ - verified: { - email: 'xxx@xxx.com' - } - }); - }); - - const spyon2 = jest.spyOn(confirmSignIn, 'changeState'); - - await confirmSignIn.checkContact({ - user: 'user' - }); - - expect(spyon2).toBeCalledWith('signedIn', {user: 'user'}); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('contact not verified', async () => { - const wrapper = shallow(); - const confirmSignIn = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'verifiedContact').mockImplementationOnce(() => { - return Promise.resolve({ - verified: {} - }); - }); - - const spyon2 = jest.spyOn(confirmSignIn, 'changeState'); - - await confirmSignIn.checkContact({ - user: 'user' - }); - - expect(spyon2).toBeCalledWith('verifyContact', {user: 'user', 'verified': {}}); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); + describe('render test', () => { + test('render correctly with Props confirmSignIn', () => { + const wrapper = shallow(); + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('render corrently with other authstate', () => { + const wrapper = shallow(); + + for (let i = 0; i < deniedStates.length; i += 1) { + wrapper.setProps({ + authState: deniedStates[i], + theme: AmplifyTheme, + }); + + expect(wrapper).toMatchSnapshot(); + } + }); + + test('hidden if hide include confirmSignIn', () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: acceptedStates[0], + hide: [ConfirmSignIn], + }); + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('confirm test', () => { + test('user with challengeName SOFTWARE_TOKEN_MFA', async () => { + const wrapper = shallow(); + + const spyon = jest + .spyOn(Auth, 'confirmSignIn') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + + wrapper.setProps({ + authState: acceptedStates[0], + theme: AmplifyTheme, + authData: { + user: { + challengeName: 'SOFTWARE_TOKEN_MFA', + }, + }, + }); + + const confirmSignIn = wrapper.instance(); + + await confirmSignIn.confirm(); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + }); + + describe('normal case', () => { + test('simulate clicking confirm button', async () => { + const spyon = jest + .spyOn(Auth, 'confirmSignIn') + .mockImplementation((user, code) => { + return new Promise((res, rej) => { + res(); + }); + }); + + const wrapper = shallow(); + const spyon2 = jest.spyOn(wrapper.instance(), 'checkContact'); + wrapper.setProps({ + authState: acceptedStates[0], + theme: AmplifyTheme, + authData: 'user', + }); + + const event_code = { + target: { + name: 'code', + value: '123456', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_code); + wrapper + .find('form') + .at(0) + .simulate('submit', fakeEvent); + + await Promise.resolve(); + + expect.assertions(3); + expect(spyon.mock.calls[0][0]).toBe('user'); + expect(spyon.mock.calls[0][1]).toBe('123456'); + expect(spyon2).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('back to sign in', () => { + const wrapper = shallow(); + const spyon2 = jest.spyOn(wrapper.instance(), 'changeState'); + wrapper.setProps({ + authState: acceptedStates[0], + theme: AmplifyTheme, + authData: 'user', + }); + + wrapper + .find(Link) + .at(0) + .simulate('click'); + expect(spyon2).toBeCalledWith('signIn'); + + spyon2.mockClear(); + }); + }); + + describe('checkContact test', () => { + test('contact verified', async () => { + const wrapper = shallow(); + const confirmSignIn = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'verifiedContact') + .mockImplementationOnce(() => { + return Promise.resolve({ + verified: { + email: 'xxx@xxx.com', + }, + }); + }); + + const spyon2 = jest.spyOn(confirmSignIn, 'changeState'); + + await confirmSignIn.checkContact({ + user: 'user', + }); + + expect(spyon2).toBeCalledWith('signedIn', { user: 'user' }); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('contact not verified', async () => { + const wrapper = shallow(); + const confirmSignIn = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'verifiedContact') + .mockImplementationOnce(() => { + return Promise.resolve({ + verified: {}, + }); + }); + + const spyon2 = jest.spyOn(confirmSignIn, 'changeState'); + + await confirmSignIn.checkContact({ + user: 'user', + }); + + expect(spyon2).toBeCalledWith('verifyContact', { + user: 'user', + verified: {}, + }); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/ConfirmSignUp-test.js b/packages/aws-amplify-react/__tests__/Auth/ConfirmSignUp-test.js index 8571a2327cb..fae3f930606 100644 --- a/packages/aws-amplify-react/__tests__/Auth/ConfirmSignUp-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/ConfirmSignUp-test.js @@ -3,145 +3,161 @@ import ConfirmSignUp from '../../src/Auth/ConfirmSignUp'; import * as React from 'react'; import AmplifyTheme from '../../src/AmplifyTheme'; import AuthPiece from '../../src/Auth/AuthPiece'; -import { Header, Footer, Input, Button, Link } from '../../src/Amplify-UI/Amplify-UI-Components-React'; +import { + Header, + Footer, + Input, + Button, + Link, +} from '../../src/Amplify-UI/Amplify-UI-Components-React'; -const acceptedStates = [ - 'confirmSignUp' -]; +const acceptedStates = ['confirmSignUp']; const deniedStates = [ - 'signIn', - 'signedUp', - 'signedOut', - 'signUp', - 'signedIn', - 'confirmSignIn', - 'forgotPassword', - 'verifyContact' + 'signIn', + 'signedUp', + 'signedOut', + 'signUp', + 'signedIn', + 'confirmSignIn', + 'forgotPassword', + 'verifyContact', ]; describe('ConfirmSignIn', () => { - describe('normal case', () => { - test('render correctly with Props confirmSignUp', () => { - const wrapper = shallow(); - for (let i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('render correctly with hide', () => { - const wrapper = shallow(); - for (let i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme, - hide: [ConfirmSignUp] - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('simulate clicking confirm button with username already defined in auth data', async () => { - const spyon = jest.spyOn(Auth, 'confirmSignUp') - .mockImplementation((user, code) => { - return new Promise((res, rej) => { - res(); - }); - }); - - const spyon3 = jest.spyOn(ConfirmSignUp.prototype, "usernameFromAuthData") - .mockImplementation(() => { - return 'user'; - }); - - const wrapper = shallow(); - const spyon2 = jest.spyOn(wrapper.instance(), 'changeState'); - wrapper.setProps({ - authState: acceptedStates[0], - theme: AmplifyTheme, - hide: false - }); - - const event_code = { - target: { - name: 'code', - value: '123456' - } - }; - - wrapper.find(Input).at(0).simulate('change', event_code); - await wrapper.find(Button).at(0).simulate('click'); - - expect.assertions(2); - expect(spyon).toBeCalledWith('user', '123456'); - expect(spyon2).toBeCalledWith('signedUp'); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - }); - - test('simulate clicking resend button with username already defined in auth data', async () => { - const spyon = jest.spyOn(Auth, 'resendSignUp') - .mockImplementation((user) => { - return new Promise((res, rej) => { - res(); - }); - }); - - const spyon3 = jest.spyOn(ConfirmSignUp.prototype, "usernameFromAuthData") - .mockImplementation(() => { - return 'user'; - }); - - const wrapper = shallow(); - - wrapper.setProps({ - authState: acceptedStates[0], - theme: AmplifyTheme, - hide: false - }); - - const event_code = { - target: { - name: 'code', - value: '123456' - } - }; - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - - await wrapper.find(Link).at(0).simulate('click'); - - expect.assertions(1); - expect(spyon).toBeCalledWith('user'); - - spyon.mockClear(); - }); - }); - - describe('null case with other authState', () => { - test('render corrently', () => { - const wrapper = shallow(); - - for (let i = 0; i < deniedStates.length; i += 1){ - wrapper.setProps({ - authState: deniedStates[i], - theme: AmplifyTheme - }); - - expect(wrapper).toMatchSnapshot(); - } - }); - }); + describe('normal case', () => { + test('render correctly with Props confirmSignUp', () => { + const wrapper = shallow(); + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('render correctly with hide', () => { + const wrapper = shallow(); + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + hide: [ConfirmSignUp], + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('simulate clicking confirm button with username already defined in auth data', async () => { + const spyon = jest + .spyOn(Auth, 'confirmSignUp') + .mockImplementation((user, code) => { + return new Promise((res, rej) => { + res(); + }); + }); + + const spyon3 = jest + .spyOn(ConfirmSignUp.prototype, 'usernameFromAuthData') + .mockImplementation(() => { + return 'user'; + }); + + const wrapper = shallow(); + const spyon2 = jest.spyOn(wrapper.instance(), 'changeState'); + wrapper.setProps({ + authState: acceptedStates[0], + theme: AmplifyTheme, + hide: false, + }); + + const event_code = { + target: { + name: 'code', + value: '123456', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_code); + await wrapper + .find(Button) + .at(0) + .simulate('click'); + + expect.assertions(2); + expect(spyon).toBeCalledWith('user', '123456'); + expect(spyon2).toBeCalledWith('signedUp'); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + }); + + test('simulate clicking resend button with username already defined in auth data', async () => { + const spyon = jest + .spyOn(Auth, 'resendSignUp') + .mockImplementation(user => { + return new Promise((res, rej) => { + res(); + }); + }); + + const spyon3 = jest + .spyOn(ConfirmSignUp.prototype, 'usernameFromAuthData') + .mockImplementation(() => { + return 'user'; + }); + + const wrapper = shallow(); + + wrapper.setProps({ + authState: acceptedStates[0], + theme: AmplifyTheme, + hide: false, + }); + + const event_code = { + target: { + name: 'code', + value: '123456', + }, + }; + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + + await wrapper + .find(Link) + .at(0) + .simulate('click'); + + expect.assertions(1); + expect(spyon).toBeCalledWith('user'); + + spyon.mockClear(); + }); + }); + + describe('null case with other authState', () => { + test('render corrently', () => { + const wrapper = shallow(); + + for (let i = 0; i < deniedStates.length; i += 1) { + wrapper.setProps({ + authState: deniedStates[i], + theme: AmplifyTheme, + }); + + expect(wrapper).toMatchSnapshot(); + } + }); + }); }); - diff --git a/packages/aws-amplify-react/__tests__/Auth/FederatedSignIn-test.js b/packages/aws-amplify-react/__tests__/Auth/FederatedSignIn-test.js index 3ab64260b9d..fe04228a334 100644 --- a/packages/aws-amplify-react/__tests__/Auth/FederatedSignIn-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/FederatedSignIn-test.js @@ -1,107 +1,109 @@ import Auth from '@aws-amplify/auth'; import * as React from 'react'; -import FederatedSignIn, { FederatedButtons } from '../../src/Auth/FederatedSignIn'; +import FederatedSignIn, { + FederatedButtons, +} from '../../src/Auth/FederatedSignIn'; const spyon = jest.spyOn(Auth, 'configure').mockImplementation(() => { - return { - hostedUIOptions: {} - }; + return { + hostedUIOptions: {}, + }; }); describe('FederatedSignIn test', () => { - describe('render test', () => { - test('render with correct authState', () => { - const wrapper = shallow(); - - wrapper.setProps({ - federated: {}, - authState: 'signIn', - onStateChange: jest.fn() - }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render nothing with incorrect authState', () => { - const wrapper = shallow(); - - wrapper.setProps({ - federated: {}, - authState: 'signedIn', - onStateChange: jest.fn() - }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render nothing with no federated prop', () => { - const wrapper = shallow(); - - wrapper.setProps({ - federated: undefined, - authState: 'signIn', - onStateChange: jest.fn() - }); - expect(wrapper).toMatchSnapshot(); - }); - }); + describe('render test', () => { + test('render with correct authState', () => { + const wrapper = shallow(); + + wrapper.setProps({ + federated: {}, + authState: 'signIn', + onStateChange: jest.fn(), + }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render nothing with incorrect authState', () => { + const wrapper = shallow(); + + wrapper.setProps({ + federated: {}, + authState: 'signedIn', + onStateChange: jest.fn(), + }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render nothing with no federated prop', () => { + const wrapper = shallow(); + + wrapper.setProps({ + federated: undefined, + authState: 'signIn', + onStateChange: jest.fn(), + }); + expect(wrapper).toMatchSnapshot(); + }); + }); }); describe('FederatedButtons test', () => { - describe('render test', () => { - test('render with correct authState', () => { - const wrapper = shallow(); - - wrapper.setProps({ - federated: { - google_client_id: 'google_client_id', - facebook_app_id: 'facebook_app_id' - }, - authState: 'signIn' - }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render with correct authState and only google id', () => { - const wrapper = shallow(); - - wrapper.setProps({ - federated: { - facebook_app_id: 'facebook_app_id' - }, - authState: 'signIn' - }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render with correct authState and only facebook id', () => { - const wrapper = shallow(); - - wrapper.setProps({ - federated: { - google_client_id: 'google_client_id' - }, - authState: 'signIn' - }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render nothing with incorrect authState', () => { - const wrapper = shallow(); - - wrapper.setProps({ - federated: {}, - authState: 'signedIn' - }); - expect(wrapper).toMatchSnapshot(); - }); - - test('render nothing with no federated prop', () => { - const wrapper = shallow(); - - wrapper.setProps({ - federated: {}, - authState: 'signIn' - }); - expect(wrapper).toMatchSnapshot(); - }); - }); + describe('render test', () => { + test('render with correct authState', () => { + const wrapper = shallow(); + + wrapper.setProps({ + federated: { + google_client_id: 'google_client_id', + facebook_app_id: 'facebook_app_id', + }, + authState: 'signIn', + }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render with correct authState and only google id', () => { + const wrapper = shallow(); + + wrapper.setProps({ + federated: { + facebook_app_id: 'facebook_app_id', + }, + authState: 'signIn', + }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render with correct authState and only facebook id', () => { + const wrapper = shallow(); + + wrapper.setProps({ + federated: { + google_client_id: 'google_client_id', + }, + authState: 'signIn', + }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render nothing with incorrect authState', () => { + const wrapper = shallow(); + + wrapper.setProps({ + federated: {}, + authState: 'signedIn', + }); + expect(wrapper).toMatchSnapshot(); + }); + + test('render nothing with no federated prop', () => { + const wrapper = shallow(); + + wrapper.setProps({ + federated: {}, + authState: 'signIn', + }); + expect(wrapper).toMatchSnapshot(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/ForgotPassword-test.js b/packages/aws-amplify-react/__tests__/Auth/ForgotPassword-test.js index cee539c1157..ff0f93ac1f2 100644 --- a/packages/aws-amplify-react/__tests__/Auth/ForgotPassword-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/ForgotPassword-test.js @@ -3,146 +3,160 @@ import ForgotPassword from '../../src/Auth/ForgotPassword'; import * as React from 'react'; import AmplifyTheme from '../../src/AmplifyTheme'; import AuthPiece from '../../src/Auth/AuthPiece'; -import { Header, Footer, Input, Button } from '../../src/Amplify-UI/Amplify-UI-Components-React'; +import { + Header, + Footer, + Input, + Button, +} from '../../src/Amplify-UI/Amplify-UI-Components-React'; -const acceptedStates = [ - 'forgotPassword' -]; +const acceptedStates = ['forgotPassword']; const deniedStates = [ - 'signIn', - 'signedUp', - 'signedOut', - 'signUp', - 'signedIn', - 'confirmSignIn', - 'confirmSignUp', - 'verifyContact' + 'signIn', + 'signedUp', + 'signedOut', + 'signUp', + 'signedIn', + 'confirmSignIn', + 'confirmSignUp', + 'verifyContact', ]; describe('forgotPassword', () => { - describe('normal case', () => { - test('render correctly with authState forgotPassword', () => { - for (let i = 0; i < acceptedStates.length; i += 1){ - const wrapper = shallow(); - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('render correctly with state delivery set', () => { - for (let i = 0; i < acceptedStates.length; i += 1){ - const wrapper = shallow(); - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme - }); - wrapper.setState({delivery: true}); - - expect(wrapper).toMatchSnapshot(); - } - }); - - test('hidden if hide include ForgotPassword', () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: acceptedStates[0], - hide: [ForgotPassword] - }); - expect(wrapper).toMatchSnapshot(); - }); - - test('simulating clicking submit', async () => { - const spyon = jest.spyOn(Auth, 'forgotPasswordSubmit') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - const wrapper = shallow(); - wrapper.setProps({ - authState: acceptedStates[0], - theme: AmplifyTheme - }); - wrapper.setState({delivery: true}); - - // const event_username = { - // target: { - // name: 'username', - // value: 'user1' - // } - // } - const event_code = { - target: { - name: 'code', - value: 'code' - } - }; - - const event_password = { - target: { - name: 'password', - value: 'abc' - } - }; - - wrapper.find(Input).at(0).simulate('change', event_code); - wrapper.find(Input).at(1).simulate('change', event_password); - - await wrapper.find(Button).simulate('click'); - - expect(spyon).toBeCalledWith(undefined, 'code', 'abc'); - - spyon.mockClear(); - }); - - test('simulating clicking send', async () => { - const spyon = jest.spyOn(Auth, 'forgotPassword') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - const wrapper = shallow(); - wrapper.setProps({ - authState: acceptedStates[0], - theme: AmplifyTheme - }); - wrapper.setState({delivery: false}); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - - wrapper.find(Input).at(0).simulate('change', event_username); - - await wrapper.find(Button).simulate('click'); - - expect(spyon).toBeCalledWith('user1'); - - spyon.mockClear(); - }); - }); - - describe('null case with other authState', () => { - test('render corrently', () => { - const wrapper = shallow(); - - for (let i = 0; i < deniedStates.length; i += 1){ - wrapper.setProps({ - authState: deniedStates[i], - theme: AmplifyTheme - }); - - expect(wrapper).toMatchSnapshot(); - } - }); - }); + describe('normal case', () => { + test('render correctly with authState forgotPassword', () => { + for (let i = 0; i < acceptedStates.length; i += 1) { + const wrapper = shallow(); + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('render correctly with state delivery set', () => { + for (let i = 0; i < acceptedStates.length; i += 1) { + const wrapper = shallow(); + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + }); + wrapper.setState({ delivery: true }); + + expect(wrapper).toMatchSnapshot(); + } + }); + + test('hidden if hide include ForgotPassword', () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: acceptedStates[0], + hide: [ForgotPassword], + }); + expect(wrapper).toMatchSnapshot(); + }); + + test('simulating clicking submit', async () => { + const spyon = jest + .spyOn(Auth, 'forgotPasswordSubmit') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + const wrapper = shallow(); + wrapper.setProps({ + authState: acceptedStates[0], + theme: AmplifyTheme, + }); + wrapper.setState({ delivery: true }); + + // const event_username = { + // target: { + // name: 'username', + // value: 'user1' + // } + // } + const event_code = { + target: { + name: 'code', + value: 'code', + }, + }; + + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_code); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + + await wrapper.find(Button).simulate('click'); + + expect(spyon).toBeCalledWith(undefined, 'code', 'abc'); + + spyon.mockClear(); + }); + + test('simulating clicking send', async () => { + const spyon = jest + .spyOn(Auth, 'forgotPassword') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + const wrapper = shallow(); + wrapper.setProps({ + authState: acceptedStates[0], + theme: AmplifyTheme, + }); + wrapper.setState({ delivery: false }); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + + await wrapper.find(Button).simulate('click'); + + expect(spyon).toBeCalledWith('user1'); + + spyon.mockClear(); + }); + }); + + describe('null case with other authState', () => { + test('render corrently', () => { + const wrapper = shallow(); + + for (let i = 0; i < deniedStates.length; i += 1) { + wrapper.setProps({ + authState: deniedStates[i], + theme: AmplifyTheme, + }); + + expect(wrapper).toMatchSnapshot(); + } + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/Greetings-test.js b/packages/aws-amplify-react/__tests__/Auth/Greetings-test.js index 18fc3dc99db..5060c35a211 100644 --- a/packages/aws-amplify-react/__tests__/Auth/Greetings-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/Greetings-test.js @@ -4,169 +4,176 @@ import Greetings from '../../src/Auth/Greetings'; import * as React from 'react'; import AmplifyTheme from '../../src/AmplifyTheme'; import AuthPiece from '../../src/Auth/AuthPiece'; -import { Header, Footer, Input, Button } from '../../src/Amplify-UI/Amplify-UI-Components-React'; +import { + Header, + Footer, + Input, + Button, +} from '../../src/Amplify-UI/Amplify-UI-Components-React'; -const acceptedStates = [ - 'signedIn' -]; +const acceptedStates = ['signedIn']; const deniedStates = [ - 'signIn', - 'signedUp', - 'signedOut', - 'forgotPassword', - 'signUp', - 'confirmSignIn', - 'confirmSignUp', - 'verifyContact' + 'signIn', + 'signedUp', + 'signedOut', + 'forgotPassword', + 'signUp', + 'confirmSignIn', + 'confirmSignUp', + 'verifyContact', ]; describe('Greetings', () => { - describe('normal case', () => { - test('render correctly with authState signedIn', () => { - const wrapper = shallow(); - for (let i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - authData: { - attributes: { - name: 'username' - } - }, - theme: 'theme' - }); - expect(wrapper).toMatchSnapshot(); - } - }); + describe('normal case', () => { + test('render correctly with authState signedIn', () => { + const wrapper = shallow(); + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + authData: { + attributes: { + name: 'username', + }, + }, + theme: 'theme', + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('render correctly with hide', () => { + const wrapper = shallow(); + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: 'theme', + hide: [Greetings], + }); + expect(wrapper).toMatchSnapshot(); + } + }); + }); + + test('render corrently with other authStates', () => { + const wrapper = shallow(); - test('render correctly with hide', () => { - const wrapper = shallow(); - for (let i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: 'theme', - hide: [Greetings] - }); - expect(wrapper).toMatchSnapshot(); - } - }); - }); + for (let i = 0; i < deniedStates.length; i += 1) { + wrapper.setProps({ + authState: deniedStates[i], + theme: 'theme', + }); - - test('render corrently with other authStates', () => { - const wrapper = shallow(); - - for (let i = 0; i < deniedStates.length; i += 1){ - wrapper.setProps({ - authState: deniedStates[i], - theme: 'theme' - }); + expect(wrapper).toMatchSnapshot(); + } + }); - expect(wrapper).toMatchSnapshot(); - } - }); - - describe('Greetings lifecycle', () => { - test('componentDidMount', async () => { - const spy = jest.spyOn(Greetings.prototype, 'componentDidMount'); - const greetings = mount().instance(); - greetings.componentDidMount(); - expect(greetings._isMounted).toBeTruthy(); - expect(spy).toHaveBeenCalled(); - spy.mockClear(); - }); - test('componentWillUnmount', async () => { - const wrapper = shallow(); - const greetings = wrapper.instance(); - const componentWillUnmount = jest.spyOn(greetings, 'componentWillUnmount'); - wrapper.unmount(); - expect(greetings._isMounted).toBeFalsy(); - expect(componentWillUnmount).toHaveBeenCalled(); - }); - }); + describe('Greetings lifecycle', () => { + test('componentDidMount', async () => { + const spy = jest.spyOn(Greetings.prototype, 'componentDidMount'); + const greetings = mount().instance(); + greetings.componentDidMount(); + expect(greetings._isMounted).toBeTruthy(); + expect(spy).toHaveBeenCalled(); + spy.mockClear(); + }); + test('componentWillUnmount', async () => { + const wrapper = shallow(); + const greetings = wrapper.instance(); + const componentWillUnmount = jest.spyOn( + greetings, + 'componentWillUnmount' + ); + wrapper.unmount(); + expect(greetings._isMounted).toBeFalsy(); + expect(componentWillUnmount).toHaveBeenCalled(); + }); + }); - describe('findState tests', () => { - test('findState is called', () => { - const spy = jest.spyOn(Greetings.prototype, 'findState'); - const greetings = mount().instance(); - expect(spy).toHaveBeenCalled(); - spy.mockClear(); - }) - test('Auth.currentAuthenticatedUser is not called if auth props are present', () => { - const spy = jest.spyOn(Auth, 'currentAuthenticatedUser') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res({ - user: {} - }); - }); - }); - const props = { - authState: 'signedIn', - authData: {} - }; - const wrapper = shallow(); - const greetings = wrapper.instance(); - expect(spy).not.toHaveBeenCalled(); - spy.mockClear(); - }) - test('Auth.currentAuthenticatedUser is called if auth props are not present', () => { - const spy = jest.spyOn(Auth, 'currentAuthenticatedUser') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res({ - user: {} - }); - }); - }); - const props = {}; - const wrapper = shallow(); - const greetings = wrapper.instance(); - expect(spy).toHaveBeenCalled(); - spy.mockClear(); - }) - test('Auth.currentAuthenticatedUser results in state being set', async() => { - const spy = jest.spyOn(Greetings.prototype, 'setState'); - const props = {}; - const wrapper = shallow(); - const greetings = wrapper.instance(); - await greetings.findState(); - expect(greetings.state.stateFromStorage).toEqual(true); - expect(spy).toHaveBeenCalled(); - spy.mockClear(); - }) - }) + describe('findState tests', () => { + test('findState is called', () => { + const spy = jest.spyOn(Greetings.prototype, 'findState'); + const greetings = mount().instance(); + expect(spy).toHaveBeenCalled(); + spy.mockClear(); + }); + test('Auth.currentAuthenticatedUser is not called if auth props are present', () => { + const spy = jest + .spyOn(Auth, 'currentAuthenticatedUser') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res({ + user: {}, + }); + }); + }); + const props = { + authState: 'signedIn', + authData: {}, + }; + const wrapper = shallow(); + const greetings = wrapper.instance(); + expect(spy).not.toHaveBeenCalled(); + spy.mockClear(); + }); + test('Auth.currentAuthenticatedUser is called if auth props are not present', () => { + const spy = jest + .spyOn(Auth, 'currentAuthenticatedUser') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res({ + user: {}, + }); + }); + }); + const props = {}; + const wrapper = shallow(); + const greetings = wrapper.instance(); + expect(spy).toHaveBeenCalled(); + spy.mockClear(); + }); + test('Auth.currentAuthenticatedUser results in state being set', async () => { + const spy = jest.spyOn(Greetings.prototype, 'setState'); + const props = {}; + const wrapper = shallow(); + const greetings = wrapper.instance(); + await greetings.findState(); + expect(greetings.state.stateFromStorage).toEqual(true); + expect(spy).toHaveBeenCalled(); + spy.mockClear(); + }); + }); - describe('onHubCapsule tests', () => { - test('onHubCapsule is present', () => { - const greetings = mount().instance(); - expect(greetings.onHubCapsule).toBeTruthy(); - }) - test('onHubCapsule is called on a Hub event', () => { - const spy = jest.spyOn(Greetings.prototype, 'onHubCapsule'); - const greetings = mount().instance(); - Hub.dispatch('auth', {event: 'test'}); - expect(spy).toHaveBeenCalled(); - spy.mockClear(); - }) - test('onHubCapsule should setState with authState = "signedIn" when "signIn" auth event fires', () => { - const spy = jest.spyOn(Greetings.prototype, 'setState'); - const greetings = mount().instance(); - Hub.dispatch('auth', {event: 'signIn', data: {foo: 'bar'}}); - expect(spy).toHaveBeenCalledWith({ - authState: 'signedIn', - authData: {foo: 'bar'} - }); - spy.mockClear(); - }) - test('onHubCapsule should setState with authState = "signIn" when "customSignOut" auth event fires', () => { - const spy = jest.spyOn(Greetings.prototype, 'setState'); - const greetings = mount().instance(); - Hub.dispatch('auth', {event: 'signOut'}); - expect(spy).toHaveBeenCalledWith({ - authState: 'signIn' - }); - spy.mockClear(); - }) - }) + describe('onHubCapsule tests', () => { + test('onHubCapsule is present', () => { + const greetings = mount().instance(); + expect(greetings.onHubCapsule).toBeTruthy(); + }); + test('onHubCapsule is called on a Hub event', () => { + const spy = jest.spyOn(Greetings.prototype, 'onHubCapsule'); + const greetings = mount().instance(); + Hub.dispatch('auth', { event: 'test' }); + expect(spy).toHaveBeenCalled(); + spy.mockClear(); + }); + test('onHubCapsule should setState with authState = "signedIn" when "signIn" auth event fires', () => { + const spy = jest.spyOn(Greetings.prototype, 'setState'); + const greetings = mount().instance(); + Hub.dispatch('auth', { event: 'signIn', data: { foo: 'bar' } }); + expect(spy).toHaveBeenCalledWith({ + authState: 'signedIn', + authData: { foo: 'bar' }, + }); + spy.mockClear(); + }); + test('onHubCapsule should setState with authState = "signIn" when "customSignOut" auth event fires', () => { + const spy = jest.spyOn(Greetings.prototype, 'setState'); + const greetings = mount().instance(); + Hub.dispatch('auth', { event: 'signOut' }); + expect(spy).toHaveBeenCalledWith({ + authState: 'signIn', + }); + spy.mockClear(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/PhoneField-test.js b/packages/aws-amplify-react/__tests__/Auth/PhoneField-test.js index 20c3c196e12..e3db2bec550 100644 --- a/packages/aws-amplify-react/__tests__/Auth/PhoneField-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/PhoneField-test.js @@ -5,42 +5,48 @@ import AuthPiece from '../../src/Auth/AuthPiece'; import { Input } from '../../src/Amplify-UI/Amplify-UI-Components-React'; describe('PhoneField', () => { - test('render correctly', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); + test('render correctly', () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); - test('trigger handleInputChange if countryCode changed', () => { - const wrapper = shallow(); - const mockOnChangeText = jest.fn(); - wrapper.setProps({ - onChangeText: mockOnChangeText - }); + test('trigger handleInputChange if countryCode changed', () => { + const wrapper = shallow(); + const mockOnChangeText = jest.fn(); + wrapper.setProps({ + onChangeText: mockOnChangeText, + }); - const event = { - target: { - name: 'countryCode', - value: '1' - } - }; - wrapper.find('select').at(0).simulate('change', event); - expect(mockOnChangeText).toBeCalled(); - }); + const event = { + target: { + name: 'countryCode', + value: '1', + }, + }; + wrapper + .find('select') + .at(0) + .simulate('change', event); + expect(mockOnChangeText).toBeCalled(); + }); - test('trigger handleInputChange if phone line number changed', () => { - const wrapper = shallow(); - const mockOnChangeText = jest.fn(); - wrapper.setProps({ - onChangeText: mockOnChangeText - }); + test('trigger handleInputChange if phone line number changed', () => { + const wrapper = shallow(); + const mockOnChangeText = jest.fn(); + wrapper.setProps({ + onChangeText: mockOnChangeText, + }); - const event = { - target: { - name: 'phone_line_number', - value: '1234567890' - } - }; - wrapper.find(Input).at(0).simulate('change', event); - expect(mockOnChangeText).toBeCalled(); - }); -}); \ No newline at end of file + const event = { + target: { + name: 'phone_line_number', + value: '1234567890', + }, + }; + wrapper + .find(Input) + .at(0) + .simulate('change', event); + expect(mockOnChangeText).toBeCalled(); + }); +}); diff --git a/packages/aws-amplify-react/__tests__/Auth/Provider/index-test.js b/packages/aws-amplify-react/__tests__/Auth/Provider/index-test.js index dc6f580dc13..6993bf7fb13 100644 --- a/packages/aws-amplify-react/__tests__/Auth/Provider/index-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/Provider/index-test.js @@ -5,16 +5,16 @@ import withGoogle from '../../../src/Auth/Provider/withGoogle'; import { withFederated } from '../../../src/Auth/Provider/index'; describe('withFederated test', () => { - describe('render test', () => { - test('render correctly', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const Comp = withFederated(MockComp); - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - }); + describe('render test', () => { + test('render correctly', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const Comp = withFederated(MockComp); + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/Provider/withAmazon-test.js b/packages/aws-amplify-react/__tests__/Auth/Provider/withAmazon-test.js index 4469e694d17..fc56fc52351 100644 --- a/packages/aws-amplify-react/__tests__/Auth/Provider/withAmazon-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/Provider/withAmazon-test.js @@ -1,338 +1,359 @@ import Auth from '@aws-amplify/auth'; import * as React from 'react'; import { Component } from 'react'; -import withAmazon, { AmazonButton } from '../../../src/Auth/Provider/withAmazon'; +import withAmazon, { + AmazonButton, +} from '../../../src/Auth/Provider/withAmazon'; import { SignInButton, Button } from '../../../src/AmplifyUI'; import { Logger } from '@aws-amplify/core'; - describe('withAmazon test', () => { - describe('render test', () => { - test('render correctly', () => { - window.amazon = 'amz'; - const MockComp = class extends Component { - render() { - return
; - } - }; - const Comp = withAmazon(MockComp); - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('signIn test', () => { - test('happy case with connected response', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - window.amazon = { - Login: { - authorize(options, callback) { - callback('response'); - } - } - }; - - const Comp = withAmazon(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - const spyon = jest.spyOn(comp, 'federatedSignIn').mockImplementationOnce(() => { return; }); - - await comp.signIn(); - - expect(spyon).toBeCalledWith('response'); - - spyon.mockClear(); - }); - - test('directly return if error happened in response', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - window.amazon = { - Login: { - authorize(options, callback) { - callback({ error: 'error' }); - } - } - }; - - - const Comp = withAmazon(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - await comp.signIn(); - }); - }); - - describe('federatedSignIn', () => { - test('happy case', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - const response = { - access_token: 'access_token', - expires_in: 0 - }; - - - window.amazon = { - Login: { - retrieveProfile(callback) { - callback({ - success: true, - profile: {Name: 'name'} - }); - } - } - }; - - - const Comp = withAmazon(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - const spyon_currentUser = jest.spyOn(Auth, 'currentAuthenticatedUser').mockImplementationOnce(() => { - return Promise.resolve('user'); - }); - - const spyon = jest.spyOn(Auth, 'federatedSignIn').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('credentials'); - }); - }); - const spyon2 = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(0); - - await comp.federatedSignIn(response); - - expect(spyon).toBeCalledWith('amazon', { expires_at: 0, token: 'access_token' }, {name: 'name' }); - - spyon.mockClear(); - spyon2.mockClear(); - spyon_currentUser.mockClear(); - }); - - test('happy case with onStateChange exists', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - const mockFn = jest.fn(); - - const response = { - access_token: 'access_token', - expires_in: 0 - }; - - window.amazon = { - Login: { - retrieveProfile(callback) { - callback({ - success: true, - profile: {Name: 'name'} - }); - } - } - }; - - - const Comp = withAmazon(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - wrapper.setProps({ - onStateChange: mockFn - }); - - const spyon_currentUser = jest.spyOn(Auth, 'currentAuthenticatedUser').mockImplementationOnce(() => { - return Promise.resolve('user'); - }); - - const spyon = jest.spyOn(Auth, 'federatedSignIn').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('credentials'); - }); - }); - const spyon2 = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(0); - - await comp.federatedSignIn(response); - - expect(spyon).toBeCalledWith('amazon', { expires_at: 0, token: 'access_token' }, {name: 'name' }); - - spyon.mockClear(); - spyon2.mockClear(); - spyon_currentUser.mockClear(); - }); - - test('directly return if access_token is null', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - const response = { - access_token: null, - expires_in: 0 - }; - - const spyon = jest.spyOn(Auth, 'federatedSignIn').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('credentials'); - }); - }); - - const spyon_currentUser = jest.spyOn(Auth, 'currentAuthenticatedUser').mockImplementationOnce(() => { - return Promise.resolve('user'); - }); - - const Comp = withAmazon(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - await comp.federatedSignIn(response); - - expect(spyon).not.toBeCalled(); - spyon.mockClear(); - spyon_currentUser.mockClear(); - }); - - test('directly return if getting userinfo failed', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - const response = { - access_token: 'access_token', - expires_in: 0 - }; - - - window.amazon = { - Login: { - retrieveProfile(callback) { - callback({ - success: false, - profile: {Name: 'name'} - }); - } - } - }; - - const Comp = withAmazon(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'federatedSignIn').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('credentials'); - }); - }); - - await comp.federatedSignIn(response); - - expect(spyon).not.toBeCalled(); - - spyon.mockClear(); - }); - }); - - describe('initAmazon test', () => { - test('happy case', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - const mockFn = jest.fn(); - const props = { - amazon_client_id: 'amazon_client_id' - }; - window.amazon = { - Login: { - setClientId: mockFn - } - }; - - const Comp = withAmazon(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - wrapper.setProps(props); - - await comp.initAmazon(); - expect(mockFn).toBeCalledWith('amazon_client_id'); - }); - }); - - describe('amazon signOut', () => { - test('happy case', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - const mockFn = jest.fn(); - - window.amazon = { - Login: { - logout: mockFn - } - }; - - const Comp = withAmazon(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - comp.signOut(); - expect(mockFn).toBeCalled(); - }); - - test('return if no amazon sdk', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - const mockFn = jest.fn(); - - window.amazon = undefined; - - const Comp = withAmazon(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - comp.signOut(); - expect(mockFn).not.toBeCalled(); - }); - }); + describe('render test', () => { + test('render correctly', () => { + window.amazon = 'amz'; + const MockComp = class extends Component { + render() { + return
; + } + }; + const Comp = withAmazon(MockComp); + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('signIn test', () => { + test('happy case with connected response', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + window.amazon = { + Login: { + authorize(options, callback) { + callback('response'); + }, + }, + }; + + const Comp = withAmazon(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + const spyon = jest + .spyOn(comp, 'federatedSignIn') + .mockImplementationOnce(() => { + return; + }); + + await comp.signIn(); + + expect(spyon).toBeCalledWith('response'); + + spyon.mockClear(); + }); + + test('directly return if error happened in response', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + window.amazon = { + Login: { + authorize(options, callback) { + callback({ error: 'error' }); + }, + }, + }; + + const Comp = withAmazon(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + await comp.signIn(); + }); + }); + + describe('federatedSignIn', () => { + test('happy case', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + const response = { + access_token: 'access_token', + expires_in: 0, + }; + + window.amazon = { + Login: { + retrieveProfile(callback) { + callback({ + success: true, + profile: { Name: 'name' }, + }); + }, + }, + }; + + const Comp = withAmazon(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + const spyon_currentUser = jest + .spyOn(Auth, 'currentAuthenticatedUser') + .mockImplementationOnce(() => { + return Promise.resolve('user'); + }); + + const spyon = jest + .spyOn(Auth, 'federatedSignIn') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('credentials'); + }); + }); + const spyon2 = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(0); + + await comp.federatedSignIn(response); + + expect(spyon).toBeCalledWith( + 'amazon', + { expires_at: 0, token: 'access_token' }, + { name: 'name' } + ); + + spyon.mockClear(); + spyon2.mockClear(); + spyon_currentUser.mockClear(); + }); + + test('happy case with onStateChange exists', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + const mockFn = jest.fn(); + + const response = { + access_token: 'access_token', + expires_in: 0, + }; + + window.amazon = { + Login: { + retrieveProfile(callback) { + callback({ + success: true, + profile: { Name: 'name' }, + }); + }, + }, + }; + + const Comp = withAmazon(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + wrapper.setProps({ + onStateChange: mockFn, + }); + + const spyon_currentUser = jest + .spyOn(Auth, 'currentAuthenticatedUser') + .mockImplementationOnce(() => { + return Promise.resolve('user'); + }); + + const spyon = jest + .spyOn(Auth, 'federatedSignIn') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('credentials'); + }); + }); + const spyon2 = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(0); + + await comp.federatedSignIn(response); + + expect(spyon).toBeCalledWith( + 'amazon', + { expires_at: 0, token: 'access_token' }, + { name: 'name' } + ); + + spyon.mockClear(); + spyon2.mockClear(); + spyon_currentUser.mockClear(); + }); + + test('directly return if access_token is null', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + const response = { + access_token: null, + expires_in: 0, + }; + + const spyon = jest + .spyOn(Auth, 'federatedSignIn') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('credentials'); + }); + }); + + const spyon_currentUser = jest + .spyOn(Auth, 'currentAuthenticatedUser') + .mockImplementationOnce(() => { + return Promise.resolve('user'); + }); + + const Comp = withAmazon(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + await comp.federatedSignIn(response); + + expect(spyon).not.toBeCalled(); + spyon.mockClear(); + spyon_currentUser.mockClear(); + }); + + test('directly return if getting userinfo failed', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + const response = { + access_token: 'access_token', + expires_in: 0, + }; + + window.amazon = { + Login: { + retrieveProfile(callback) { + callback({ + success: false, + profile: { Name: 'name' }, + }); + }, + }, + }; + + const Comp = withAmazon(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'federatedSignIn') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('credentials'); + }); + }); + + await comp.federatedSignIn(response); + + expect(spyon).not.toBeCalled(); + + spyon.mockClear(); + }); + }); + + describe('initAmazon test', () => { + test('happy case', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + const mockFn = jest.fn(); + const props = { + amazon_client_id: 'amazon_client_id', + }; + window.amazon = { + Login: { + setClientId: mockFn, + }, + }; + + const Comp = withAmazon(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + wrapper.setProps(props); + + await comp.initAmazon(); + expect(mockFn).toBeCalledWith('amazon_client_id'); + }); + }); + + describe('amazon signOut', () => { + test('happy case', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + const mockFn = jest.fn(); + + window.amazon = { + Login: { + logout: mockFn, + }, + }; + + const Comp = withAmazon(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + comp.signOut(); + expect(mockFn).toBeCalled(); + }); + + test('return if no amazon sdk', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + const mockFn = jest.fn(); + + window.amazon = undefined; + + const Comp = withAmazon(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + comp.signOut(); + expect(mockFn).not.toBeCalled(); + }); + }); }); describe('AmazonButton test', () => { - describe('render test', () => { - test('render correctly', () => { - window.amazon = 'amz'; - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - }); + describe('render test', () => { + test('render correctly', () => { + window.amazon = 'amz'; + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + }); + }); }); - diff --git a/packages/aws-amplify-react/__tests__/Auth/Provider/withAuth0-test.js b/packages/aws-amplify-react/__tests__/Auth/Provider/withAuth0-test.js index 392dd8c30b8..5c644bb0b39 100644 --- a/packages/aws-amplify-react/__tests__/Auth/Provider/withAuth0-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/Provider/withAuth0-test.js @@ -4,220 +4,226 @@ import withAuth0, { Auth0Button } from '../../../src/Auth/Provider/withAuth0'; import { SignInButton, Button } from '../../../src/AmplifyUI'; const auth0_config = { - domain: 'your auth0 domain', - clientID: 'your client id', - redirectUri: 'your call back url', - audience: 'https://your_domain/userinfo', - responseType: 'token id_token', // for now we only support implicit grant flow - scope: 'openid profile email', // the scope used by your app - returnTo: 'your sign out url' + domain: 'your auth0 domain', + clientID: 'your client id', + redirectUri: 'your call back url', + audience: 'https://your_domain/userinfo', + responseType: 'token id_token', // for now we only support implicit grant flow + scope: 'openid profile email', // the scope used by your app + returnTo: 'your sign out url', }; describe('withAuth0 test', () => { - describe('render test', () => { - test('render correctly', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - const Comp = withAuth0(MockComp); - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('signIn test', () => { - test('happy case', async () => { - const MockComp = class extends Component { - render() { - return
; - } - } - const mockFn = jest.fn(); - - const Comp = withAuth0(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - - comp._auth0 = { - authorize: mockFn - }; - try { - await comp.signIn(); - expect(mockFn).toBeCalled(); - } catch (e){ - } - }); - }); - - describe('initialize test', () => { - test('happy case', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const mockFn = jest.fn().mockImplementationOnce((callback) => { - callback(null, { - idToken: 'idToken', - expiresIn: 3000, - accessToken: 'accessToken' - }); - }); - const mockFn2 = jest.fn().mockImplementationOnce((token, callback) => { - callback(null, { - name: 'name', - email: 'email' - }); - }); - const spyon = jest.spyOn(Auth, 'federatedSignIn').mockImplementationOnce(() => { - return Promise.resolve(); - }); - - const Comp = withAuth0(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - - comp._auth0 = { - parseHash: mockFn, - client: { - userInfo: mockFn2 - } - }; - - comp.initialize(); - expect(mockFn).toBeCalled(); - expect(mockFn2).toBeCalled(); - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - - test('return if parse hash failed', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const mockFn = jest.fn().mockImplementationOnce((callback) => { - callback('err', null); - }); - const mockFn2 = jest.fn().mockImplementationOnce((token, callback) => { - callback(null, { - name: 'name', - email: 'email' - }); - }); - const spyon = jest.spyOn(Auth, 'federatedSignIn').mockImplementationOnce(() => { - return Promise.resolve(); - }); - - const Comp = withAuth0(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - - comp._auth0 = { - parseHash: mockFn, - client: { - userInfo: mockFn2 - } - }; - - comp.initialize(); - expect(mockFn).toBeCalled(); - expect(mockFn2).not.toBeCalled(); - expect(spyon).not.toBeCalled(); - }); - - test('directly return if in signedin state', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const mockFn = jest.fn().mockImplementationOnce((callback) => { - callback('err', null); - }); - const mockFn2 = jest.fn().mockImplementationOnce((token, callback) => { - callback(null, { - name: 'name', - email: 'email' - }); - }); - const spyon = jest.spyOn(Auth, 'federatedSignIn').mockImplementationOnce(() => { - return Promise.resolve(); - }); - - const Comp = withAuth0(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - - comp._auth0 = { - parseHash: mockFn, - client: { - userInfo: mockFn2 - } - }; - - comp.initialize(); - expect(mockFn).not.toBeCalled(); - expect(mockFn2).not.toBeCalled(); - expect(spyon).not.toBeCalled(); - }); - - test('directly return if no auth0 config', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const mockFn = jest.fn().mockImplementationOnce((callback) => { - callback('err', null); - }); - const mockFn2 = jest.fn().mockImplementationOnce((token, callback) => { - callback(null, { - name: 'name', - email: 'email' - }); - }); - const spyon = jest.spyOn(Auth, 'federatedSignIn').mockImplementationOnce(() => { - return Promise.resolve(); - }); - - const Comp = withAuth0(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - - comp._auth0 = { - parseHash: mockFn, - client: { - userInfo: mockFn2 - } - }; - - comp.initialize(); - expect(mockFn).not.toBeCalled(); - expect(mockFn2).not.toBeCalled(); - expect(spyon).not.toBeCalled(); - }); - }); + describe('render test', () => { + test('render correctly', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + const Comp = withAuth0(MockComp); + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('signIn test', () => { + test('happy case', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const mockFn = jest.fn(); + + const Comp = withAuth0(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + comp._auth0 = { + authorize: mockFn, + }; + try { + await comp.signIn(); + expect(mockFn).toBeCalled(); + } catch (e) {} + }); + }); + + describe('initialize test', () => { + test('happy case', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const mockFn = jest.fn().mockImplementationOnce(callback => { + callback(null, { + idToken: 'idToken', + expiresIn: 3000, + accessToken: 'accessToken', + }); + }); + const mockFn2 = jest.fn().mockImplementationOnce((token, callback) => { + callback(null, { + name: 'name', + email: 'email', + }); + }); + const spyon = jest + .spyOn(Auth, 'federatedSignIn') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + + const Comp = withAuth0(MockComp); + const wrapper = shallow( + + ); + const comp = wrapper.instance(); + + comp._auth0 = { + parseHash: mockFn, + client: { + userInfo: mockFn2, + }, + }; + + comp.initialize(); + expect(mockFn).toBeCalled(); + expect(mockFn2).toBeCalled(); + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + + test('return if parse hash failed', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const mockFn = jest.fn().mockImplementationOnce(callback => { + callback('err', null); + }); + const mockFn2 = jest.fn().mockImplementationOnce((token, callback) => { + callback(null, { + name: 'name', + email: 'email', + }); + }); + const spyon = jest + .spyOn(Auth, 'federatedSignIn') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + + const Comp = withAuth0(MockComp); + const wrapper = shallow( + + ); + const comp = wrapper.instance(); + + comp._auth0 = { + parseHash: mockFn, + client: { + userInfo: mockFn2, + }, + }; + + comp.initialize(); + expect(mockFn).toBeCalled(); + expect(mockFn2).not.toBeCalled(); + expect(spyon).not.toBeCalled(); + }); + + test('directly return if in signedin state', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const mockFn = jest.fn().mockImplementationOnce(callback => { + callback('err', null); + }); + const mockFn2 = jest.fn().mockImplementationOnce((token, callback) => { + callback(null, { + name: 'name', + email: 'email', + }); + }); + const spyon = jest + .spyOn(Auth, 'federatedSignIn') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + + const Comp = withAuth0(MockComp); + const wrapper = shallow( + + ); + const comp = wrapper.instance(); + + comp._auth0 = { + parseHash: mockFn, + client: { + userInfo: mockFn2, + }, + }; + + comp.initialize(); + expect(mockFn).not.toBeCalled(); + expect(mockFn2).not.toBeCalled(); + expect(spyon).not.toBeCalled(); + }); + + test('directly return if no auth0 config', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const mockFn = jest.fn().mockImplementationOnce(callback => { + callback('err', null); + }); + const mockFn2 = jest.fn().mockImplementationOnce((token, callback) => { + callback(null, { + name: 'name', + email: 'email', + }); + }); + const spyon = jest + .spyOn(Auth, 'federatedSignIn') + .mockImplementationOnce(() => { + return Promise.resolve(); + }); + + const Comp = withAuth0(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + comp._auth0 = { + parseHash: mockFn, + client: { + userInfo: mockFn2, + }, + }; + + comp.initialize(); + expect(mockFn).not.toBeCalled(); + expect(mockFn2).not.toBeCalled(); + expect(spyon).not.toBeCalled(); + }); + }); }); describe('Auth0Button test', () => { - describe('render test', () => { - test('render correctly', () => { - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - }); -}); + describe('render test', () => { + test('render correctly', () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/aws-amplify-react/__tests__/Auth/Provider/withFacebook-test.js b/packages/aws-amplify-react/__tests__/Auth/Provider/withFacebook-test.js index 9a118a05292..cb136a0e4ba 100644 --- a/packages/aws-amplify-react/__tests__/Auth/Provider/withFacebook-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/Provider/withFacebook-test.js @@ -1,374 +1,393 @@ import Auth from '@aws-amplify/auth'; import * as React from 'react'; import { Component } from 'react'; -import withFacebook, { FacebookButton } from '../../../src/Auth/Provider/withFacebook'; +import withFacebook, { + FacebookButton, +} from '../../../src/Auth/Provider/withFacebook'; import { SignInButton, Button } from '../../../src/AmplifyUI'; - describe('withFacebook test', () => { - describe('render test', () => { - test('render correctly', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - window.FB = 'fb'; - const Comp = withFacebook(MockComp); - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('signIn test', () => { - test('happy case with connected response', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const fbResponse = { - status: 'connected', - authResponse: { - token: 'token' - } - }; - - - window.FB = { - getLoginStatus(callback) { - callback(fbResponse); - } - }; - - - const Comp = withFacebook(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - const spyon = jest.spyOn(comp, 'federatedSignIn').mockImplementationOnce(() => { return; }); - - comp.signIn(); - - expect(spyon).toBeCalledWith(fbResponse.authResponse); - - spyon.mockClear(); - }); - - test('happy case with not connected response', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const fbResponse = { - authResponse: { token: null }, - status: 'not connected' - }; - - const fbResponse2 = { - authResponse: { - authResponse: { token: 'token' }, - status: 'connected' - } - }; - - - window.FB = { - getLoginStatus(callback) { - callback(fbResponse); - }, - login(callback, option) { - callback(fbResponse2); - } - }; - - - const Comp = withFacebook(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - const spyon = jest.spyOn(comp, 'federatedSignIn').mockImplementationOnce(() => { return; }); - - comp.signIn(); - - expect(spyon).toBeCalledWith(fbResponse2.authResponse); - - spyon.mockClear(); - }); - - test('return if pop up window closed', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const fbResponse = { - authResponse: { token: null }, - status: 'not connected' - }; - - const fbResponse2 = { - authResponse: null - }; - - - window.FB = { - getLoginStatus(callback) { - callback(fbResponse); - }, - login(callback, option) { - callback(fbResponse2); - } - }; - - - const Comp = withFacebook(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - const spyon = jest.spyOn(comp, 'federatedSignIn').mockImplementationOnce(() => { return; }); - - comp.signIn(); - - expect(spyon).not.toBeCalled(); - - spyon.mockClear(); - }); - }); - - describe('federatedSignIn', () => { - test('happy case', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const fbResponse = { - name: 'username', - email: 'user@example.com' - }; - - window.FB = { - api(path, {}, callback) { - callback(fbResponse); - } - }; - - - const Comp = withFacebook(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'federatedSignIn').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('credentials'); - }); - }); - const spyon2 = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(0); - - const spyon_currentUser = jest.spyOn(Auth, 'currentAuthenticatedUser').mockImplementationOnce(() => { - return Promise.resolve('user'); - }); - - await comp.federatedSignIn({ - accessToken: 'accessToken', - expiresIn: 0 - }); - - expect(spyon).toBeCalledWith( - 'facebook', - { token: 'accessToken', expires_at: 0 }, { name: 'username', email: 'user@example.com' } - ); - - spyon.mockClear(); - spyon2.mockClear(); - spyon_currentUser.mockClear(); - }); - - test('happy case with onStateChange exists', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const fbResponse = { - name: 'username', - email: 'user@example.com' - }; - - window.FB = { - api(path, {}, callback) { - callback(fbResponse); - } - }; - - const mockFn = jest.fn(); - - const Comp = withFacebook(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - const spyon_currentUser = jest.spyOn(Auth, 'currentAuthenticatedUser').mockImplementationOnce(() => { - return 'user'; - }); - - const spyon = jest.spyOn(Auth, 'federatedSignIn').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('credentials'); - }); - }); - const spyon2 = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(0); - - wrapper.setProps({ - onStateChange: mockFn - }); - - await comp.federatedSignIn({ - accessToken: 'accessToken', - expiresIn: 0 - }); - - expect(spyon).toBeCalledWith( - 'facebook', - { token: 'accessToken', expires_at: 0 }, { name: 'username', email: 'user@example.com' } - ); - - spyon.mockClear(); - spyon2.mockClear(); - spyon_currentUser.mockClear(); - }); - - test('directly return if no accesstoken', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const fbResponse = { - name: 'username' - }; - - window.FB = { - api(path, callback) { - callback(fbResponse); - } - }; - - - const Comp = withFacebook(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'federatedSignIn').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('credentials'); - }); - }); - - const spyon_currentUser = jest.spyOn(Auth, 'currentAuthenticatedUser').mockImplementationOnce(() => { - return Promise.resolve('user'); - }); - - await comp.federatedSignIn({ - accessToken: null, - }); - - expect(spyon).not.toBeCalled(); - - spyon.mockClear(); - spyon_currentUser.mockClear(); - }); - }); - - describe('fbAsyncInit test', () => { - test('happy case', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - const mockFn = jest.fn().mockImplementationOnce((callback) => { - callback('response'); - }); - const mockFn2 = jest.fn(); - window.FB = { - getLoginStatus: mockFn, - init: mockFn2 - }; - - const Comp = withFacebook(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - comp.fbAsyncInit(); - - expect(mockFn).toBeCalled(); - expect(mockFn2).toBeCalled(); - }); - }); - - describe('facebook signout test', () => { - test('happy case', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - - const mockFn = jest.fn(); - - window.FB = { - getLoginStatus(callback) { - callback({ - status: 'connected' - }); - }, - logout: mockFn - }; - - const Comp = withFacebook(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - await comp.signOut(); - expect(mockFn).toBeCalled(); - }); - - test('not connected', async () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const mockFn = jest.fn(); - - window.FB = { - getLoginStatus(callback) { - callback({ - status: 'not connected' - }); - }, - logout: mockFn - }; - const Comp = withFacebook(MockComp); - const wrapper = shallow(); - const comp = wrapper.instance(); - - await comp.signOut(); - expect(mockFn).not.toBeCalled(); - }); - }); + describe('render test', () => { + test('render correctly', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + window.FB = 'fb'; + const Comp = withFacebook(MockComp); + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('signIn test', () => { + test('happy case with connected response', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const fbResponse = { + status: 'connected', + authResponse: { + token: 'token', + }, + }; + + window.FB = { + getLoginStatus(callback) { + callback(fbResponse); + }, + }; + + const Comp = withFacebook(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + const spyon = jest + .spyOn(comp, 'federatedSignIn') + .mockImplementationOnce(() => { + return; + }); + + comp.signIn(); + + expect(spyon).toBeCalledWith(fbResponse.authResponse); + + spyon.mockClear(); + }); + + test('happy case with not connected response', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const fbResponse = { + authResponse: { token: null }, + status: 'not connected', + }; + + const fbResponse2 = { + authResponse: { + authResponse: { token: 'token' }, + status: 'connected', + }, + }; + + window.FB = { + getLoginStatus(callback) { + callback(fbResponse); + }, + login(callback, option) { + callback(fbResponse2); + }, + }; + + const Comp = withFacebook(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + const spyon = jest + .spyOn(comp, 'federatedSignIn') + .mockImplementationOnce(() => { + return; + }); + + comp.signIn(); + + expect(spyon).toBeCalledWith(fbResponse2.authResponse); + + spyon.mockClear(); + }); + + test('return if pop up window closed', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const fbResponse = { + authResponse: { token: null }, + status: 'not connected', + }; + + const fbResponse2 = { + authResponse: null, + }; + + window.FB = { + getLoginStatus(callback) { + callback(fbResponse); + }, + login(callback, option) { + callback(fbResponse2); + }, + }; + + const Comp = withFacebook(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + const spyon = jest + .spyOn(comp, 'federatedSignIn') + .mockImplementationOnce(() => { + return; + }); + + comp.signIn(); + + expect(spyon).not.toBeCalled(); + + spyon.mockClear(); + }); + }); + + describe('federatedSignIn', () => { + test('happy case', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const fbResponse = { + name: 'username', + email: 'user@example.com', + }; + + window.FB = { + api(path, {}, callback) { + callback(fbResponse); + }, + }; + + const Comp = withFacebook(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'federatedSignIn') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('credentials'); + }); + }); + const spyon2 = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(0); + + const spyon_currentUser = jest + .spyOn(Auth, 'currentAuthenticatedUser') + .mockImplementationOnce(() => { + return Promise.resolve('user'); + }); + + await comp.federatedSignIn({ + accessToken: 'accessToken', + expiresIn: 0, + }); + + expect(spyon).toBeCalledWith( + 'facebook', + { token: 'accessToken', expires_at: 0 }, + { name: 'username', email: 'user@example.com' } + ); + + spyon.mockClear(); + spyon2.mockClear(); + spyon_currentUser.mockClear(); + }); + + test('happy case with onStateChange exists', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const fbResponse = { + name: 'username', + email: 'user@example.com', + }; + + window.FB = { + api(path, {}, callback) { + callback(fbResponse); + }, + }; + + const mockFn = jest.fn(); + + const Comp = withFacebook(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + const spyon_currentUser = jest + .spyOn(Auth, 'currentAuthenticatedUser') + .mockImplementationOnce(() => { + return 'user'; + }); + + const spyon = jest + .spyOn(Auth, 'federatedSignIn') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('credentials'); + }); + }); + const spyon2 = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(0); + + wrapper.setProps({ + onStateChange: mockFn, + }); + + await comp.federatedSignIn({ + accessToken: 'accessToken', + expiresIn: 0, + }); + + expect(spyon).toBeCalledWith( + 'facebook', + { token: 'accessToken', expires_at: 0 }, + { name: 'username', email: 'user@example.com' } + ); + + spyon.mockClear(); + spyon2.mockClear(); + spyon_currentUser.mockClear(); + }); + + test('directly return if no accesstoken', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const fbResponse = { + name: 'username', + }; + + window.FB = { + api(path, callback) { + callback(fbResponse); + }, + }; + + const Comp = withFacebook(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'federatedSignIn') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('credentials'); + }); + }); + + const spyon_currentUser = jest + .spyOn(Auth, 'currentAuthenticatedUser') + .mockImplementationOnce(() => { + return Promise.resolve('user'); + }); + + await comp.federatedSignIn({ + accessToken: null, + }); + + expect(spyon).not.toBeCalled(); + + spyon.mockClear(); + spyon_currentUser.mockClear(); + }); + }); + + describe('fbAsyncInit test', () => { + test('happy case', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + const mockFn = jest.fn().mockImplementationOnce(callback => { + callback('response'); + }); + const mockFn2 = jest.fn(); + window.FB = { + getLoginStatus: mockFn, + init: mockFn2, + }; + + const Comp = withFacebook(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + comp.fbAsyncInit(); + + expect(mockFn).toBeCalled(); + expect(mockFn2).toBeCalled(); + }); + }); + + describe('facebook signout test', () => { + test('happy case', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + + const mockFn = jest.fn(); + + window.FB = { + getLoginStatus(callback) { + callback({ + status: 'connected', + }); + }, + logout: mockFn, + }; + + const Comp = withFacebook(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + await comp.signOut(); + expect(mockFn).toBeCalled(); + }); + + test('not connected', async () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const mockFn = jest.fn(); + + window.FB = { + getLoginStatus(callback) { + callback({ + status: 'not connected', + }); + }, + logout: mockFn, + }; + const Comp = withFacebook(MockComp); + const wrapper = shallow(); + const comp = wrapper.instance(); + + await comp.signOut(); + expect(mockFn).not.toBeCalled(); + }); + }); }); describe('FacebookButton test', () => { - describe('render test', () => { - test('render correctly', () => { - window.FB = 'fb'; - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - }); + describe('render test', () => { + test('render correctly', () => { + window.FB = 'fb'; + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/Provider/withOAuth-test.js b/packages/aws-amplify-react/__tests__/Auth/Provider/withOAuth-test.js index 80c5342c493..d10261577c8 100644 --- a/packages/aws-amplify-react/__tests__/Auth/Provider/withOAuth-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/Provider/withOAuth-test.js @@ -5,62 +5,62 @@ import withOAuth, { OAuthButton } from '../../../src/Auth/Provider/withOAuth'; import { SignInButton, Button } from '../../../src/AmplifyUI'; describe('withOAuth test', () => { - describe('render test', () => { - test('render correctly', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; + describe('render test', () => { + test('render correctly', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; - const Comp = withOAuth(MockComp); - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); + const Comp = withOAuth(MockComp); + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); - test('render correctly with button', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - }); + test('render correctly with button', () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); + }); - describe('signIn test', () => { - test('happy case with connected response', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; + describe('signIn test', () => { + test('happy case with connected response', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; - const spyon = jest.spyOn(Auth, 'federatedSignIn'); - - const Comp = withOAuth(MockComp); - const wrapper = mount(); - const comp = wrapper.instance(); + const spyon = jest.spyOn(Auth, 'federatedSignIn'); - comp.signIn(); + const Comp = withOAuth(MockComp); + const wrapper = mount(); + const comp = wrapper.instance(); - expect(spyon).toBeCalledWith({ provider: undefined }); - spyon.mockClear(); - }); + comp.signIn(); - test('Passing in a social provider', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; + expect(spyon).toBeCalledWith({ provider: undefined }); + spyon.mockClear(); + }); - const spyon = jest.spyOn(Auth, 'federatedSignIn'); - - const Comp = withOAuth(MockComp); - const wrapper = mount(); - const comp = wrapper.instance(); + test('Passing in a social provider', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; - comp.signIn(expect.anything(), 'Facebook'); + const spyon = jest.spyOn(Auth, 'federatedSignIn'); - expect(spyon).toBeCalledWith({"provider": "Facebook"}); - spyon.mockClear(); - }); - }); + const Comp = withOAuth(MockComp); + const wrapper = mount(); + const comp = wrapper.instance(); + + comp.signIn(expect.anything(), 'Facebook'); + + expect(spyon).toBeCalledWith({ provider: 'Facebook' }); + spyon.mockClear(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/RequireNewPassword-test.js b/packages/aws-amplify-react/__tests__/Auth/RequireNewPassword-test.js index 42422b64c0e..fb95e54366b 100644 --- a/packages/aws-amplify-react/__tests__/Auth/RequireNewPassword-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/RequireNewPassword-test.js @@ -4,346 +4,386 @@ import { Button, Link } from '../../src/Amplify-UI/Amplify-UI-Components-React'; import RequireNewPassword from '../../src/Auth/RequireNewPassword'; describe('RequireNewPassword test', () => { - describe('render test', () => { - test('render correctly', () => { - const wrapper = shallow(); - - wrapper.setProps({ - authState: 'requireNewPassword', - authData: { - challengeParam: { - requiredAttributes: [] - } - }, - hide: false - }); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render correctly with required attributes', () => { - const wrapper = shallow(); - - wrapper.setProps({ - authState: 'requireNewPassword', - authData: { - challengeParam: { - requiredAttributes: ['given_name', 'family_name'] - } - }, - hide: false - }); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render nothing with incorrect authState', () => { - const wrapper = shallow(); - - wrapper.setProps({ - authState: 'signIn', - hide: false - }); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render nothing with hide', () => { - const wrapper = shallow(); - - wrapper.setProps({ - authState: 'requireNewPassword', - hide: [RequireNewPassword] - }); - - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('interaction test', () => { - test('ButtonRow clicked', () => { - const spyon = jest.spyOn(RequireNewPassword.prototype, 'change').mockImplementationOnce(() => { return; }); - - const wrapper = shallow(); - - wrapper.setProps({ - authState: 'requireNewPassword', - authData: { - challengeParam: { - requiredAttributes: [] - } - }, - hide: false - }); - - wrapper.find(Button).simulate('click'); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - - test('Link clicked', () => { - const spyon = jest - .spyOn(RequireNewPassword.prototype, 'changeState') - .mockImplementationOnce(() => { return; }); - - const wrapper = shallow(); - - wrapper.setProps({ - authState: 'requireNewPassword', - authData: { - challengeParam: { - requiredAttributes: [] - } - }, - hide: false - }); - - wrapper.find(Link).simulate('click'); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - }); - - describe('change test', () => { - test('happy case', async () => { - const props = { - authData: { - challengeParam: { - requiredAttributes: [] - } - } - }; - - const spyon = jest.spyOn(Auth, 'completeNewPassword').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('user'); - }); - }); - const spyon2 = jest - .spyOn(RequireNewPassword.prototype, 'checkContact') - .mockImplementationOnce(() => { return; }); - - const wrapper = shallow(); - const requireNewPassword = wrapper.instance(); - - wrapper.setProps(props); - requireNewPassword.inputs = { - password: 'password' - }; - - await requireNewPassword.change(); - - expect(spyon).toBeCalledWith( - { "challengeParam": { "requiredAttributes": [] } }, - 'password', - {} - ); - - expect(spyon2).toBeCalledWith('user'); - spyon.mockClear(); - }); - - test('confirm sign in case', async () => { - const props = { - authData: { - challengeParam: { - requiredAttributes: [] - } - } - }; - - const spyon = jest.spyOn(Auth, 'completeNewPassword').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res({ - challengeName: 'SMS_MFA' - }); - }); - }); - const spyon2 = jest - .spyOn(RequireNewPassword.prototype, 'changeState') - .mockImplementationOnce(() => { return; }); - - const wrapper = shallow(); - const requireNewPassword = wrapper.instance(); - - wrapper.setProps(props); - requireNewPassword.inputs = { - password: 'password' - }; - - await requireNewPassword.change(); - - expect(spyon).toBeCalledWith( - { "challengeParam": { "requiredAttributes": [] } }, - 'password', - {} - ); - - expect(spyon2).toBeCalledWith('confirmSignIn', { challengeName: 'SMS_MFA' }); - spyon.mockClear(); - }); - - test('totp setup case', async () => { - const props = { - authData: { - challengeParam: { - requiredAttributes: [] - } - } - }; - - const spyon = jest.spyOn(Auth, 'completeNewPassword').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res({ - challengeName: 'MFA_SETUP' - }); - }); - }); - const spyon2 = jest - .spyOn(RequireNewPassword.prototype, 'changeState') - .mockImplementationOnce(() => { return; }); - - const wrapper = shallow(); - const requireNewPassword = wrapper.instance(); - - wrapper.setProps(props); - requireNewPassword.inputs = { - password: 'password' - }; - - await requireNewPassword.change(); - - expect(spyon).toBeCalledWith( - { "challengeParam": { "requiredAttributes": [] } }, - 'password', - {} - ); - - expect(spyon2).toBeCalledWith('TOTPSetup', { challengeName: 'MFA_SETUP' }); - spyon.mockClear(); - }); - - test('error happened with Auth completeNewPasword', async () => { - const props = { - authData: { - challengeParam: { - requiredAttributes: 'requiredAttributes' - } - } - }; - - const spyon = jest.spyOn(Auth, 'completeNewPassword').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - const spyon2 = jest.spyOn(RequireNewPassword.prototype, 'error').mockImplementationOnce(() => { return; }); - - const wrapper = shallow(); - const requireNewPassword = wrapper.instance(); - - wrapper.setProps(props); - requireNewPassword.inputs = { - password: 'password' - }; - - await requireNewPassword.change(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('requiredAttributes test', async () => { - const props = { - authData: { - challengeParam: { - requiredAttributes: ['given_name', 'family_name'] - } - } - }; - - const spyon = jest.spyOn(Auth, 'completeNewPassword').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('user'); - }); - }); - const spyon2 = jest - .spyOn(RequireNewPassword.prototype, 'checkContact') - .mockImplementationOnce(() => { return; }); - - const wrapper = shallow(); - const requireNewPassword = wrapper.instance(); - - wrapper.setProps(props); - requireNewPassword.inputs = { - password: 'password', - given_name: 'Max', - family_name: 'Power' - }; - - await requireNewPassword.change(); - - expect(spyon).toBeCalledWith( - { "challengeParam": { "requiredAttributes": ['given_name', 'family_name'] } }, - 'password', - { given_name: 'Max', family_name: 'Power' } - ); - - expect(spyon2).toBeCalledWith('user'); - spyon.mockClear(); - }); - }); - - describe('checkContact test', () => { - test('contact verified', async () => { - const wrapper = shallow(); - const rnp = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'verifiedContact').mockImplementationOnce(() => { - return Promise.resolve({ - verified: { - email: 'xxx@xxx.com' - } - }); - }); - - const spyon2 = jest.spyOn(rnp, 'changeState'); - - await rnp.checkContact({ - user: 'user' - }); - - expect(spyon2).toBeCalledWith('signedIn', { user: 'user' }); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('contact not verified', async () => { - const wrapper = shallow(); - const rnp = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'verifiedContact').mockImplementationOnce(() => { - return Promise.resolve({ - verified: {} - }); - }); - - const spyon2 = jest.spyOn(rnp, 'changeState'); - - await rnp.checkContact({ - user: 'user' - }); - - expect(spyon2).toBeCalledWith('verifyContact', { user: 'user', 'verified': {} }); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); + describe('render test', () => { + test('render correctly', () => { + const wrapper = shallow(); + + wrapper.setProps({ + authState: 'requireNewPassword', + authData: { + challengeParam: { + requiredAttributes: [], + }, + }, + hide: false, + }); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render correctly with required attributes', () => { + const wrapper = shallow(); + + wrapper.setProps({ + authState: 'requireNewPassword', + authData: { + challengeParam: { + requiredAttributes: ['given_name', 'family_name'], + }, + }, + hide: false, + }); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render nothing with incorrect authState', () => { + const wrapper = shallow(); + + wrapper.setProps({ + authState: 'signIn', + hide: false, + }); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render nothing with hide', () => { + const wrapper = shallow(); + + wrapper.setProps({ + authState: 'requireNewPassword', + hide: [RequireNewPassword], + }); + + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('interaction test', () => { + test('ButtonRow clicked', () => { + const spyon = jest + .spyOn(RequireNewPassword.prototype, 'change') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + + wrapper.setProps({ + authState: 'requireNewPassword', + authData: { + challengeParam: { + requiredAttributes: [], + }, + }, + hide: false, + }); + + wrapper.find(Button).simulate('click'); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + + test('Link clicked', () => { + const spyon = jest + .spyOn(RequireNewPassword.prototype, 'changeState') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + + wrapper.setProps({ + authState: 'requireNewPassword', + authData: { + challengeParam: { + requiredAttributes: [], + }, + }, + hide: false, + }); + + wrapper.find(Link).simulate('click'); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + }); + + describe('change test', () => { + test('happy case', async () => { + const props = { + authData: { + challengeParam: { + requiredAttributes: [], + }, + }, + }; + + const spyon = jest + .spyOn(Auth, 'completeNewPassword') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('user'); + }); + }); + const spyon2 = jest + .spyOn(RequireNewPassword.prototype, 'checkContact') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const requireNewPassword = wrapper.instance(); + + wrapper.setProps(props); + requireNewPassword.inputs = { + password: 'password', + }; + + await requireNewPassword.change(); + + expect(spyon).toBeCalledWith( + { challengeParam: { requiredAttributes: [] } }, + 'password', + {} + ); + + expect(spyon2).toBeCalledWith('user'); + spyon.mockClear(); + }); + + test('confirm sign in case', async () => { + const props = { + authData: { + challengeParam: { + requiredAttributes: [], + }, + }, + }; + + const spyon = jest + .spyOn(Auth, 'completeNewPassword') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res({ + challengeName: 'SMS_MFA', + }); + }); + }); + const spyon2 = jest + .spyOn(RequireNewPassword.prototype, 'changeState') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const requireNewPassword = wrapper.instance(); + + wrapper.setProps(props); + requireNewPassword.inputs = { + password: 'password', + }; + + await requireNewPassword.change(); + + expect(spyon).toBeCalledWith( + { challengeParam: { requiredAttributes: [] } }, + 'password', + {} + ); + + expect(spyon2).toBeCalledWith('confirmSignIn', { + challengeName: 'SMS_MFA', + }); + spyon.mockClear(); + }); + + test('totp setup case', async () => { + const props = { + authData: { + challengeParam: { + requiredAttributes: [], + }, + }, + }; + + const spyon = jest + .spyOn(Auth, 'completeNewPassword') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res({ + challengeName: 'MFA_SETUP', + }); + }); + }); + const spyon2 = jest + .spyOn(RequireNewPassword.prototype, 'changeState') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const requireNewPassword = wrapper.instance(); + + wrapper.setProps(props); + requireNewPassword.inputs = { + password: 'password', + }; + + await requireNewPassword.change(); + + expect(spyon).toBeCalledWith( + { challengeParam: { requiredAttributes: [] } }, + 'password', + {} + ); + + expect(spyon2).toBeCalledWith('TOTPSetup', { + challengeName: 'MFA_SETUP', + }); + spyon.mockClear(); + }); + + test('error happened with Auth completeNewPasword', async () => { + const props = { + authData: { + challengeParam: { + requiredAttributes: 'requiredAttributes', + }, + }, + }; + + const spyon = jest + .spyOn(Auth, 'completeNewPassword') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + const spyon2 = jest + .spyOn(RequireNewPassword.prototype, 'error') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const requireNewPassword = wrapper.instance(); + + wrapper.setProps(props); + requireNewPassword.inputs = { + password: 'password', + }; + + await requireNewPassword.change(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('requiredAttributes test', async () => { + const props = { + authData: { + challengeParam: { + requiredAttributes: ['given_name', 'family_name'], + }, + }, + }; + + const spyon = jest + .spyOn(Auth, 'completeNewPassword') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('user'); + }); + }); + const spyon2 = jest + .spyOn(RequireNewPassword.prototype, 'checkContact') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const requireNewPassword = wrapper.instance(); + + wrapper.setProps(props); + requireNewPassword.inputs = { + password: 'password', + given_name: 'Max', + family_name: 'Power', + }; + + await requireNewPassword.change(); + + expect(spyon).toBeCalledWith( + { + challengeParam: { requiredAttributes: ['given_name', 'family_name'] }, + }, + 'password', + { given_name: 'Max', family_name: 'Power' } + ); + + expect(spyon2).toBeCalledWith('user'); + spyon.mockClear(); + }); + }); + + describe('checkContact test', () => { + test('contact verified', async () => { + const wrapper = shallow(); + const rnp = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'verifiedContact') + .mockImplementationOnce(() => { + return Promise.resolve({ + verified: { + email: 'xxx@xxx.com', + }, + }); + }); + + const spyon2 = jest.spyOn(rnp, 'changeState'); + + await rnp.checkContact({ + user: 'user', + }); + + expect(spyon2).toBeCalledWith('signedIn', { user: 'user' }); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('contact not verified', async () => { + const wrapper = shallow(); + const rnp = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'verifiedContact') + .mockImplementationOnce(() => { + return Promise.resolve({ + verified: {}, + }); + }); + + const spyon2 = jest.spyOn(rnp, 'changeState'); + + await rnp.checkContact({ + user: 'user', + }); + + expect(spyon2).toBeCalledWith('verifyContact', { + user: 'user', + verified: {}, + }); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); }); - diff --git a/packages/aws-amplify-react/__tests__/Auth/SignIn-test.js b/packages/aws-amplify-react/__tests__/Auth/SignIn-test.js index 3aa5f513709..1fb68b9a32f 100644 --- a/packages/aws-amplify-react/__tests__/Auth/SignIn-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/SignIn-test.js @@ -3,334 +3,395 @@ import SignIn from '../../src/Auth/SignIn'; import * as React from 'react'; import AmplifyTheme from '../../src/AmplifyTheme'; import AuthPiece from '../../src/Auth/AuthPiece'; -import { Header, Footer, Input, Button } from '../../src/Amplify-UI/Amplify-UI-Components-React'; +import { + Header, + Footer, + Input, + Button, +} from '../../src/Amplify-UI/Amplify-UI-Components-React'; const acceptedStates = [ - 'signIn', - 'signedUp', - 'signedOut', - 'customConfirmSignIn' + 'signIn', + 'signedUp', + 'signedOut', + 'customConfirmSignIn', ]; const deniedStates = [ - 'signUp', - 'signedIn', - 'comfirmSignIn', - 'confirmSignUp', - 'forgotPassword', - 'verifyContact' + 'signUp', + 'signedIn', + 'comfirmSignIn', + 'confirmSignUp', + 'forgotPassword', + 'verifyContact', ]; const fakeEvent = { - preventDefault: jest.fn() + preventDefault: jest.fn(), }; describe('SignIn', () => { - describe('normal case', () => { - test('render correctly with Props signIn, signedOut or signedUp', () => { - for (let i = 0; i < acceptedStates.length; i += 1){ - const wrapper = shallow(); - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme - }); - - expect(wrapper).toMatchSnapshot(); - } - }); - - test('render correctly with hide', () => { - for (let i = 0; i < acceptedStates.length; i += 1){ - const wrapper = shallow(); - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme, - hide: [SignIn] - }); - - expect(wrapper).toMatchSnapshot(); - } - }); - - test('when clicking signIn and new password required', async () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: 'signIn', - theme: AmplifyTheme - }); - - const spyon = jest.spyOn(Auth, 'signIn') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res({ - challengeName: 'NEW_PASSWORD_REQUIRED' - }); - }); - }); - - const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - const event_password = { - target: { - name: 'password', - value: 'abc' - } - }; - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - wrapper.find('form').at(0).simulate('submit', fakeEvent); - - await Promise.resolve(); - - expect(spyon.mock.calls.length).toBe(1); - expect(spyon.mock.calls[0][0]).toBe(event_username.target.value); - expect(spyon.mock.calls[0][1]).toBe(event_password.target.value); - - expect(spyon_changeState).toBeCalled(); - expect(spyon_changeState.mock.calls[0][0]).toBe('requireNewPassword'); - - spyon.mockClear(); - spyon_changeState.mockClear(); - }); - - test('when clicking signIn and trigger-based custom auth challenge present required', async () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: 'signIn', - theme: AmplifyTheme - }); - - const spyon = jest.spyOn(Auth, 'signIn') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res({ - challengeName: 'CUSTOM_CHALLENGE', - challengeParam: { trigger: 'true' } - }); - }); - }); - - const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - const event_password = { - target: { - name: 'password', - value: 'abc' - } - }; - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - wrapper.find('form').at(0).simulate('submit', fakeEvent); - - await Promise.resolve(); - - expect(spyon.mock.calls.length).toBe(1); - expect(spyon.mock.calls[0][0]).toBe(event_username.target.value); - expect(spyon.mock.calls[0][1]).toBe(event_password.target.value); - - expect(spyon_changeState).toBeCalled(); - expect(spyon_changeState.mock.calls[0][0]).toBe('customConfirmSignIn'); - - spyon.mockClear(); - spyon_changeState.mockClear(); - }); - - test('when clicking signIn and user session null, need verification of email and phone', async () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: 'signIn', - theme: AmplifyTheme - }); - - const spyon = jest.spyOn(Auth, 'signIn') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res({ - Session: null - }); - }); - }); - - const spyon2 = jest.spyOn(Auth, 'userAttributes') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res([{ - Name: 'email', - Value: 'email_val' - }, { - Name: 'phone_number', - Value: 'phone_number' - }]); - }); - }); - - const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - const event_password = { - target: { - name: 'password', - value: 'abc' - } - }; - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - wrapper.find('form').at(0).simulate('submit', fakeEvent); - - // expect(spyon_changeState).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - spyon_changeState.mockClear(); - }); - - test('when clicking signIn and user session null, dont need verification', async () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: 'signIn', - theme: AmplifyTheme - }); - - const spyon = jest.spyOn(Auth, 'signIn') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res({ - Session: null - }); - }); - }); - - const spyon2 = jest.spyOn(Auth, 'userAttributes') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res([{ - Name: 'email_verfied', - Value: true - }, { - Name: 'phone_number_verified', - Value: true - }]); - }); - }); - - const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - const event_password = { - target: { - name: 'password', - value: 'abc' - } - }; - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - wrapper.find('form').at(0).simulate('submit', fakeEvent); - - // expect(spyon_changeState).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - spyon_changeState.mockClear(); - }); - - test('when clicking signIn and error happend', async () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: 'signIn', - theme: AmplifyTheme - }); - - const spyon = jest.spyOn(Auth, 'signIn') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - const spyon2 = jest.spyOn(wrapper.instance(), 'error'); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - const event_password = { - target: { - name: 'password', - value: 'abc' - } - }; - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - - wrapper.find('form').at(0).simulate('submit', fakeEvent); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); - - describe('null case with other authState', () => { - test('render corrently', () => { - const wrapper = shallow(); - - for (let i = 0; i < deniedStates.length; i += 1){ - wrapper.setProps({ - authState: deniedStates[i], - theme: AmplifyTheme - }); - - expect(wrapper).toMatchSnapshot(); - } - }); - - }); - - describe('sign in test', () => { - test('UserNotConfirmedException, change state to confirmSignUp', async () => { - const wrapper = shallow(); - const signIn = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'signIn').mockImplementationOnce(() => { - return Promise.reject({ - code: 'UserNotConfirmedException' - }); - }); - - const spyon2 = jest.spyOn(signIn, 'changeState'); - await signIn.signIn(fakeEvent); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); + describe('normal case', () => { + test('render correctly with Props signIn, signedOut or signedUp', () => { + for (let i = 0; i < acceptedStates.length; i += 1) { + const wrapper = shallow(); + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + }); + + expect(wrapper).toMatchSnapshot(); + } + }); + + test('render correctly with hide', () => { + for (let i = 0; i < acceptedStates.length; i += 1) { + const wrapper = shallow(); + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + hide: [SignIn], + }); + + expect(wrapper).toMatchSnapshot(); + } + }); + + test('when clicking signIn and new password required', async () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: 'signIn', + theme: AmplifyTheme, + }); + + const spyon = jest + .spyOn(Auth, 'signIn') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res({ + challengeName: 'NEW_PASSWORD_REQUIRED', + }); + }); + }); + + const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + wrapper + .find('form') + .at(0) + .simulate('submit', fakeEvent); + + await Promise.resolve(); + + expect(spyon.mock.calls.length).toBe(1); + expect(spyon.mock.calls[0][0]).toBe(event_username.target.value); + expect(spyon.mock.calls[0][1]).toBe(event_password.target.value); + + expect(spyon_changeState).toBeCalled(); + expect(spyon_changeState.mock.calls[0][0]).toBe('requireNewPassword'); + + spyon.mockClear(); + spyon_changeState.mockClear(); + }); + + test('when clicking signIn and trigger-based custom auth challenge present required', async () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: 'signIn', + theme: AmplifyTheme, + }); + + const spyon = jest + .spyOn(Auth, 'signIn') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res({ + challengeName: 'CUSTOM_CHALLENGE', + challengeParam: { trigger: 'true' }, + }); + }); + }); + + const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + wrapper + .find('form') + .at(0) + .simulate('submit', fakeEvent); + + await Promise.resolve(); + + expect(spyon.mock.calls.length).toBe(1); + expect(spyon.mock.calls[0][0]).toBe(event_username.target.value); + expect(spyon.mock.calls[0][1]).toBe(event_password.target.value); + + expect(spyon_changeState).toBeCalled(); + expect(spyon_changeState.mock.calls[0][0]).toBe('customConfirmSignIn'); + + spyon.mockClear(); + spyon_changeState.mockClear(); + }); + + test('when clicking signIn and user session null, need verification of email and phone', async () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: 'signIn', + theme: AmplifyTheme, + }); + + const spyon = jest + .spyOn(Auth, 'signIn') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res({ + Session: null, + }); + }); + }); + + const spyon2 = jest + .spyOn(Auth, 'userAttributes') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res([ + { + Name: 'email', + Value: 'email_val', + }, + { + Name: 'phone_number', + Value: 'phone_number', + }, + ]); + }); + }); + + const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + wrapper + .find('form') + .at(0) + .simulate('submit', fakeEvent); + + // expect(spyon_changeState).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + spyon_changeState.mockClear(); + }); + + test('when clicking signIn and user session null, dont need verification', async () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: 'signIn', + theme: AmplifyTheme, + }); + + const spyon = jest + .spyOn(Auth, 'signIn') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res({ + Session: null, + }); + }); + }); + + const spyon2 = jest + .spyOn(Auth, 'userAttributes') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res([ + { + Name: 'email_verfied', + Value: true, + }, + { + Name: 'phone_number_verified', + Value: true, + }, + ]); + }); + }); + + const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + wrapper + .find('form') + .at(0) + .simulate('submit', fakeEvent); + + // expect(spyon_changeState).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + spyon_changeState.mockClear(); + }); + + test('when clicking signIn and error happend', async () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: 'signIn', + theme: AmplifyTheme, + }); + + const spyon = jest + .spyOn(Auth, 'signIn') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + const spyon2 = jest.spyOn(wrapper.instance(), 'error'); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + + wrapper + .find('form') + .at(0) + .simulate('submit', fakeEvent); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); + + describe('null case with other authState', () => { + test('render corrently', () => { + const wrapper = shallow(); + + for (let i = 0; i < deniedStates.length; i += 1) { + wrapper.setProps({ + authState: deniedStates[i], + theme: AmplifyTheme, + }); + + expect(wrapper).toMatchSnapshot(); + } + }); + }); + + describe('sign in test', () => { + test('UserNotConfirmedException, change state to confirmSignUp', async () => { + const wrapper = shallow(); + const signIn = wrapper.instance(); + + const spyon = jest.spyOn(Auth, 'signIn').mockImplementationOnce(() => { + return Promise.reject({ + code: 'UserNotConfirmedException', + }); + }); + + const spyon2 = jest.spyOn(signIn, 'changeState'); + await signIn.signIn(fakeEvent); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); }); - diff --git a/packages/aws-amplify-react/__tests__/Auth/SignOut-test.js b/packages/aws-amplify-react/__tests__/Auth/SignOut-test.js index 7c7c3ac183d..391c7edcaba 100644 --- a/packages/aws-amplify-react/__tests__/Auth/SignOut-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/SignOut-test.js @@ -7,220 +7,219 @@ import { Header, Footer, InputRow, ButtonRow } from '../../src/AmplifyUI'; import { Hub } from '@aws-amplify/core'; import * as AmplifyMocks from '../../__mocks__/amplifyMock'; -const acceptedStates = [ - 'signedIn' -]; +const acceptedStates = ['signedIn']; const deniedStates = [ - 'signIn', - 'signedUp', - 'signedOut', - 'forgotPassword', - 'signUp', - 'confirmSignIn', - 'confirmSignUp', - 'verifyContact' + 'signIn', + 'signedUp', + 'signedOut', + 'forgotPassword', + 'signUp', + 'confirmSignIn', + 'confirmSignUp', + 'verifyContact', ]; describe('SignOut', () => { - describe('normal case', () => { - test('render correctly with authState signedIn', () => { - const wrapper = shallow(); - for (let i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: 'theme' - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('render correctly with hide', () => { - const wrapper = shallow(); - for (let i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: 'theme', - hide: [SignOut] - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('render correctly with empty hide', () => { - const wrapper = shallow(); - for (let i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: 'theme', - hide: [] - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - }); - - test('render correctly with other authStates', () => { - const wrapper = shallow(); - - for (let i = 0; i < deniedStates.length; i += 1){ - wrapper.setProps({ - authState: deniedStates[i], - theme: 'theme' - }); - - expect(wrapper).toMatchSnapshot(); - } - }); - - describe('signOut test', () => { - test('happy case (without stateFromStorage)', async () => { - const wrapper = shallow(); - const signOut = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'signOut').mockImplementationOnce(() => { - return Promise.resolve(); - }); - - await signOut.signOut(); - - expect(spyon).toBeCalled(); - spyon.mockClear(); - }); - - test('happy case (with stateFromStorage)', async () => { - const wrapper = shallow(); - const signOut = wrapper.instance(); - - signOut.state.stateFromStorage = true; - - const spyon = jest.spyOn(Auth, 'signOut').mockImplementationOnce(() => { - return Promise.resolve(); - }); - - await signOut.signOut(); - - expect(spyon).toBeCalled(); - spyon.mockClear(); - }); - - test('error case', async () => { - const wrapper = shallow(); - const signOut = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'signOut').mockImplementationOnce(() => { - return Promise.reject('error'); - }); - - await signOut.signOut(); - - expect(spyon).toBeCalled(); - spyon.mockClear(); - }); - }); - - describe('onHubCapsule tests', () => { - test('onHubCapsule is present', () => { - const signOut = mount().instance(); - expect(signOut.onHubCapsule).toBeTruthy(); - }) - test('onHubCapsule is called on a Hub event', () => { - const spy = jest.spyOn(SignOut.prototype, 'onHubCapsule'); - mount().instance(); - Hub.dispatch('auth', {event: 'test'}); - expect(spy).toHaveBeenCalled(); - spy.mockClear(); - }) - test('onHubCapsule should setState with authState = "signedIn" when "signIn" auth event fires', () => { - const spy = jest.spyOn(SignOut.prototype, 'setState'); - mount().instance(); - Hub.dispatch('auth', {event: 'signIn', data: {foo: 'bar'}}); - expect(spy).toHaveBeenCalledWith({ - authState: 'signedIn', - authData: {foo: 'bar'} - }); - spy.mockClear(); - }) - test('onHubCapsule should setState with authState = "signIn" when "customSignOut" auth event fires', () => { - const spy = jest.spyOn(SignOut.prototype, 'setState'); - mount().instance(); - Hub.dispatch('auth', {event: 'signOut'}); - expect(spy).toHaveBeenCalledWith({ - authState: 'signIn' - }); - spy.mockClear(); - }) - }) - - describe('findState tests', () => { - test('findState is called', () => { - const spy = jest.spyOn(SignOut.prototype, 'findState'); - mount().instance(); - expect(spy).toHaveBeenCalled(); - spy.mockClear(); - }) - test('Auth.currentAuthenticatedUser is not called if auth props are present', () => { - const spy = jest.spyOn(Auth, 'currentAuthenticatedUser') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res({ - user: {} - }); - }); - }); - const props = { - authState: 'signedIn', - authData: {} - }; - const wrapper = shallow(); - wrapper.instance(); - expect(spy).not.toHaveBeenCalled(); - spy.mockClear(); - }) - test('Auth.currentAuthenticatedUser is called if auth props are not present', () => { - const spy = jest.spyOn(Auth, 'currentAuthenticatedUser') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res({ - user: {} - }); - }); - }); - const props = {}; - const wrapper = shallow(); - wrapper.instance(); - expect(spy).toHaveBeenCalled(); - spy.mockClear(); - }) - test('Auth.currentAuthenticatedUser results in state being set', async() => { - const spy = jest.spyOn(SignOut.prototype, 'setState'); - const props = {}; - const wrapper = shallow(); - const signOut = wrapper.instance(); - await signOut.findState(); - expect(signOut.state.stateFromStorage).toEqual(true); - expect(spy).toHaveBeenCalled(); - spy.mockClear(); - }) - }) - - describe('SignOut lifecycle', () => { - test('componentDidMount', async () => { - const spy = jest.spyOn(SignOut.prototype, 'componentDidMount'); - const signOut = mount().instance(); - signOut.componentDidMount(); - expect(signOut._isMounted).toBeTruthy(); - expect(spy).toHaveBeenCalled(); - spy.mockClear(); - }); - test('componentWillUnmount', async () => { - const wrapper = shallow(); - const signOut = wrapper.instance(); - const componentWillUnmount = jest.spyOn(signOut, 'componentWillUnmount'); - wrapper.unmount(); - expect(signOut._isMounted).toBeFalsy(); - expect(componentWillUnmount).toHaveBeenCalled(); - }); - }); + describe('normal case', () => { + test('render correctly with authState signedIn', () => { + const wrapper = shallow(); + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: 'theme', + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('render correctly with hide', () => { + const wrapper = shallow(); + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: 'theme', + hide: [SignOut], + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('render correctly with empty hide', () => { + const wrapper = shallow(); + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: 'theme', + hide: [], + }); + expect(wrapper).toMatchSnapshot(); + } + }); + }); + + test('render correctly with other authStates', () => { + const wrapper = shallow(); + + for (let i = 0; i < deniedStates.length; i += 1) { + wrapper.setProps({ + authState: deniedStates[i], + theme: 'theme', + }); + + expect(wrapper).toMatchSnapshot(); + } + }); + + describe('signOut test', () => { + test('happy case (without stateFromStorage)', async () => { + const wrapper = shallow(); + const signOut = wrapper.instance(); + + const spyon = jest.spyOn(Auth, 'signOut').mockImplementationOnce(() => { + return Promise.resolve(); + }); + + await signOut.signOut(); + + expect(spyon).toBeCalled(); + spyon.mockClear(); + }); + + test('happy case (with stateFromStorage)', async () => { + const wrapper = shallow(); + const signOut = wrapper.instance(); + + signOut.state.stateFromStorage = true; + + const spyon = jest.spyOn(Auth, 'signOut').mockImplementationOnce(() => { + return Promise.resolve(); + }); + + await signOut.signOut(); + + expect(spyon).toBeCalled(); + spyon.mockClear(); + }); + + test('error case', async () => { + const wrapper = shallow(); + const signOut = wrapper.instance(); + + const spyon = jest.spyOn(Auth, 'signOut').mockImplementationOnce(() => { + return Promise.reject('error'); + }); + + await signOut.signOut(); + + expect(spyon).toBeCalled(); + spyon.mockClear(); + }); + }); + + describe('onHubCapsule tests', () => { + test('onHubCapsule is present', () => { + const signOut = mount().instance(); + expect(signOut.onHubCapsule).toBeTruthy(); + }); + test('onHubCapsule is called on a Hub event', () => { + const spy = jest.spyOn(SignOut.prototype, 'onHubCapsule'); + mount().instance(); + Hub.dispatch('auth', { event: 'test' }); + expect(spy).toHaveBeenCalled(); + spy.mockClear(); + }); + test('onHubCapsule should setState with authState = "signedIn" when "signIn" auth event fires', () => { + const spy = jest.spyOn(SignOut.prototype, 'setState'); + mount().instance(); + Hub.dispatch('auth', { event: 'signIn', data: { foo: 'bar' } }); + expect(spy).toHaveBeenCalledWith({ + authState: 'signedIn', + authData: { foo: 'bar' }, + }); + spy.mockClear(); + }); + test('onHubCapsule should setState with authState = "signIn" when "customSignOut" auth event fires', () => { + const spy = jest.spyOn(SignOut.prototype, 'setState'); + mount().instance(); + Hub.dispatch('auth', { event: 'signOut' }); + expect(spy).toHaveBeenCalledWith({ + authState: 'signIn', + }); + spy.mockClear(); + }); + }); + + describe('findState tests', () => { + test('findState is called', () => { + const spy = jest.spyOn(SignOut.prototype, 'findState'); + mount().instance(); + expect(spy).toHaveBeenCalled(); + spy.mockClear(); + }); + test('Auth.currentAuthenticatedUser is not called if auth props are present', () => { + const spy = jest + .spyOn(Auth, 'currentAuthenticatedUser') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res({ + user: {}, + }); + }); + }); + const props = { + authState: 'signedIn', + authData: {}, + }; + const wrapper = shallow(); + wrapper.instance(); + expect(spy).not.toHaveBeenCalled(); + spy.mockClear(); + }); + test('Auth.currentAuthenticatedUser is called if auth props are not present', () => { + const spy = jest + .spyOn(Auth, 'currentAuthenticatedUser') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res({ + user: {}, + }); + }); + }); + const props = {}; + const wrapper = shallow(); + wrapper.instance(); + expect(spy).toHaveBeenCalled(); + spy.mockClear(); + }); + test('Auth.currentAuthenticatedUser results in state being set', async () => { + const spy = jest.spyOn(SignOut.prototype, 'setState'); + const props = {}; + const wrapper = shallow(); + const signOut = wrapper.instance(); + await signOut.findState(); + expect(signOut.state.stateFromStorage).toEqual(true); + expect(spy).toHaveBeenCalled(); + spy.mockClear(); + }); + }); + + describe('SignOut lifecycle', () => { + test('componentDidMount', async () => { + const spy = jest.spyOn(SignOut.prototype, 'componentDidMount'); + const signOut = mount().instance(); + signOut.componentDidMount(); + expect(signOut._isMounted).toBeTruthy(); + expect(spy).toHaveBeenCalled(); + spy.mockClear(); + }); + test('componentWillUnmount', async () => { + const wrapper = shallow(); + const signOut = wrapper.instance(); + const componentWillUnmount = jest.spyOn(signOut, 'componentWillUnmount'); + wrapper.unmount(); + expect(signOut._isMounted).toBeFalsy(); + expect(componentWillUnmount).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/SignUp-test.js b/packages/aws-amplify-react/__tests__/Auth/SignUp-test.js index 1f45bd8e50c..09afadfc958 100644 --- a/packages/aws-amplify-react/__tests__/Auth/SignUp-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/SignUp-test.js @@ -3,701 +3,799 @@ import SignUp from '../../src/Auth/SignUp'; import * as React from 'react'; import AmplifyTheme from '../../src/AmplifyTheme'; import AuthPiece from '../../src/Auth/AuthPiece'; -import { Header, Footer, Input, Button, SelectInput, InputLabel } from '../../src/Amplify-UI/Amplify-UI-Components-React'; +import { + Header, + Footer, + Input, + Button, + SelectInput, + InputLabel, +} from '../../src/Amplify-UI/Amplify-UI-Components-React'; import { PhoneField } from '../../src/Auth/PhoneField'; -const acceptedStates = [ - 'signUp' -]; +const acceptedStates = ['signUp']; const deniedStates = [ - 'signIn', - 'signedUp', - 'signedOut', - 'forgotPassword', - 'signedIn', - 'confirmSignIn', - 'confirmSignUp', - 'verifyContact' + 'signIn', + 'signedUp', + 'signedOut', + 'forgotPassword', + 'signedIn', + 'confirmSignIn', + 'confirmSignUp', + 'verifyContact', ]; const mockResult = { - user: { - username: 'testuser' - } -} + user: { + username: 'testuser', + }, +}; describe('signUp without signUpConfig prop', () => { - describe('normal case', () => { - const wrapper = shallow(); - - test('render correctly with authState signUp', () => { - for (let i = 0; i < acceptedStates.length; i += 1) { - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('render correctly with hide', () => { - for (let i = 0; i < acceptedStates.length; i += 1) { - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme, - hide: [SignUp] - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('when clicking signUp', async () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme - }); - - const spyon = jest.spyOn(Auth, 'signUp') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res(mockResult); - }); - }); - - const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - const event_password = { - target: { - name: 'password', - value: 'abc' - } - }; - - const event_email = { - target: { - name: 'email', - value: 'email@amazon.com' - } - }; - const phone_number = '+12345678999'; - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - wrapper.find(Input).at(2).simulate('change', event_email); - wrapper.find(PhoneField).at(0).simulate('changeText', phone_number); - await wrapper.find(Button).simulate('click'); - - - expect(spyon).toBeCalledWith({"attributes": {"email": "email@amazon.com", "phone_number": "+12345678999"}, "password": "abc", "username": "user1"}); - expect(spyon_changeState).toBeCalled(); - expect(spyon_changeState.mock.calls[0][0]).toBe('confirmSignUp'); - - spyon.mockClear(); - spyon_changeState.mockClear(); - }); - - test('when clicking signUp with another format of phone number', async () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme - }); - - const spyon = jest.spyOn(Auth, 'signUp') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res(mockResult); - }); - }); - - const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - const event_password = { - target: { - name: 'password', - value: 'abc' - } - }; - - const event_email = { - target: { - name: 'email', - value: 'email@amazon.com' - } - }; - - const phone_number = '+12345678901'; - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - wrapper.find(Input).at(2).simulate('change', event_email); - wrapper.find(PhoneField).at(0).simulate('changeText', phone_number); - await wrapper.find(Button).simulate('click'); - - expect(spyon) - .toBeCalledWith({ - "attributes": { "email": "email@amazon.com", "phone_number": "+12345678901" }, - "password": "abc", - "username": "user1" - }); - - expect(spyon_changeState).toBeCalled(); - expect(spyon_changeState.mock.calls[0][0]).toBe('confirmSignUp'); - - spyon.mockClear(); - spyon_changeState.mockClear(); - }); - - test('when clicking signUp without phone_number', async () => { - const wrapper = shallow(); - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme - }); - - const spyon = jest.spyOn(Auth, 'signUp') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res(mockResult); - }); - }); - - const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - }; - const event_password = { - target: { - name: 'password', - value: 'abc' - } - }; - - const event_email = { - target: { - name: 'email', - value: 'email@amazon.com' - } - }; - - const phone_number = undefined; - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - wrapper.find(Input).at(2).simulate('change', event_email); - wrapper.find(PhoneField).at(0).simulate('changeText', phone_number); - await wrapper.find(Button).simulate('click'); - - - expect(spyon).not.toBeCalled(); - - spyon.mockClear(); - spyon_changeState.mockClear(); - }); - }); - - describe('null case with other authState', () => { - test('render corrently', () => { - const wrapper = shallow(); - - for (let i = 0; i < deniedStates.length; i += 1) { - wrapper.setProps({ - authState: deniedStates[i], - theme: AmplifyTheme - }); - - expect(wrapper).toMatchSnapshot(); - } - }); - }); + describe('normal case', () => { + const wrapper = shallow(); + + test('render correctly with authState signUp', () => { + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('render correctly with hide', () => { + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + hide: [SignUp], + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('when clicking signUp', async () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + }); + + const spyon = jest + .spyOn(Auth, 'signUp') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res(mockResult); + }); + }); + + const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + const event_email = { + target: { + name: 'email', + value: 'email@amazon.com', + }, + }; + const phone_number = '+12345678999'; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + wrapper + .find(Input) + .at(2) + .simulate('change', event_email); + wrapper + .find(PhoneField) + .at(0) + .simulate('changeText', phone_number); + await wrapper.find(Button).simulate('click'); + + expect(spyon).toBeCalledWith({ + attributes: { email: 'email@amazon.com', phone_number: '+12345678999' }, + password: 'abc', + username: 'user1', + }); + expect(spyon_changeState).toBeCalled(); + expect(spyon_changeState.mock.calls[0][0]).toBe('confirmSignUp'); + + spyon.mockClear(); + spyon_changeState.mockClear(); + }); + + test('when clicking signUp with another format of phone number', async () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + }); + + const spyon = jest + .spyOn(Auth, 'signUp') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res(mockResult); + }); + }); + + const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + const event_email = { + target: { + name: 'email', + value: 'email@amazon.com', + }, + }; + + const phone_number = '+12345678901'; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + wrapper + .find(Input) + .at(2) + .simulate('change', event_email); + wrapper + .find(PhoneField) + .at(0) + .simulate('changeText', phone_number); + await wrapper.find(Button).simulate('click'); + + expect(spyon).toBeCalledWith({ + attributes: { email: 'email@amazon.com', phone_number: '+12345678901' }, + password: 'abc', + username: 'user1', + }); + + expect(spyon_changeState).toBeCalled(); + expect(spyon_changeState.mock.calls[0][0]).toBe('confirmSignUp'); + + spyon.mockClear(); + spyon_changeState.mockClear(); + }); + + test('when clicking signUp without phone_number', async () => { + const wrapper = shallow(); + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + }); + + const spyon = jest + .spyOn(Auth, 'signUp') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res(mockResult); + }); + }); + + const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + const event_email = { + target: { + name: 'email', + value: 'email@amazon.com', + }, + }; + + const phone_number = undefined; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + wrapper + .find(Input) + .at(2) + .simulate('change', event_email); + wrapper + .find(PhoneField) + .at(0) + .simulate('changeText', phone_number); + await wrapper.find(Button).simulate('click'); + + expect(spyon).not.toBeCalled(); + + spyon.mockClear(); + spyon_changeState.mockClear(); + }); + }); + + describe('null case with other authState', () => { + test('render corrently', () => { + const wrapper = shallow(); + + for (let i = 0; i < deniedStates.length; i += 1) { + wrapper.setProps({ + authState: deniedStates[i], + theme: AmplifyTheme, + }); + + expect(wrapper).toMatchSnapshot(); + } + }); + }); }); describe('signUp with signUpConfig', () => { - let wrapper; - beforeEach(() => { - wrapper = shallow(); - }) - - test('render correctly with authState signUp', () => { - for (var i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme, - signUpConfig: { - signUpFields: [ - { - key: 'address', - label: 'Address', - required: true - } - ] - } - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('render correctly with hide', () => { - for (var i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme, - hide: [SignUp], - signUpConfig: { - signUpFields: [ - { - key: 'address', - label: 'Address', - required: true - } - ] - } - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('expect custom field to be last if display order not defined', () => { - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme, - signUpConfig: { - signUpFields: [ - { - key: 'address', - label: 'Address', - required: true - } - ] - } - }); - const addressElementFound = wrapper.find({name: 'address'}); - const addressChildFound = wrapper.find(Input).at(3); - expect(addressElementFound.props().name).toEqual(addressChildFound.props().name); - }); - - test('expect custom field to be first if display order is defined as 1, and it is prior to username alpabetically', () => { - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme, - signUpConfig: { - signUpFields: [ - { - key: 'address', - label: 'Address', - required: true, - displayOrder: 1 - } - ] - } - }); - const addressElementFound = wrapper.find({name: 'address'}); - const addressChildFound = wrapper.find(Input).at(0); - expect(addressElementFound.props().name).toEqual(addressChildFound.props().name); - }); - - test('expect custom field to be second if display order is defined as 1, and it is after username alpabetically', () => { - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme, - signUpConfig: { - signUpFields: [ - { - key: 'z', - label: 'Z', - required: true, - displayOrder: 1 - } - ] - } - }); - const addressElementFound = wrapper.find({name: 'z'}); - const addressChildFound = wrapper.find(Input).at(1); - expect(addressElementFound.props().name).toEqual(addressChildFound.props().name); - }); - - test('expect 5 fields to be present if hideAllDefaults is undefined', () => { - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme, - signUpConfig: { - signUpFields: [ - { - key: 'z', - label: 'Z', - required: true, - displayOrder: 1 - } - ] - } - }); - expect(wrapper.find(Input).length).toEqual(4); - expect(wrapper.find(PhoneField).length).toEqual(1); - }); - - test('expect 5 fields to be present if hideAllDefaults is false', () => { - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme, - signUpConfig: { - hideAllDefaults: false, - signUpFields: [ - { - key: 'z', - label: 'Z', - required: true, - displayOrder: 1 - } - ] - } - }); - expect(wrapper.find(Input).length).toEqual(4); - expect(wrapper.find(PhoneField).length).toEqual(1); - }); - - test('expect custom field to be the only field if hideAllDefaults is true', () => { - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme, - signUpConfig: { - hideAllDefaults: true, - signUpFields: [ - { - key: 'z', - label: 'Z', - required: true, - displayOrder: 1 - } - ] - } - }); - expect(wrapper.find(Input).length).toEqual(1); - }); - - test('expect default username to be overwritten if username field passed in via signUpConfig', () => { - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme, - signUpConfig: { - signUpFields: [ - { - key: 'z', - label: 'Z', - required: true, - }, - { - key: 'username', - label: 'NEW USERNAME LABEL', - required: true, - } - ] - } - }); - - const signup = new SignUp; - const defaultUsernameLabel = signup.defaultSignUpFields.find((i) => { - return i.key === 'username' - }).label; - - const customUsername = wrapper.find(InputLabel).findWhere((el) => { - return el.text() === 'NEW USERNAME LABEL'; - }); - - const originalUsername = wrapper.find(InputLabel).findWhere((el) => { - return el.text() === defaultUsernameLabel; - }); - - expect(customUsername.length).toEqual(1); - expect(originalUsername.length).toEqual(0); - }); - - test('default dial code should be set to passed defaultCountryCode', () => { - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme, - signUpConfig: { - defaultCountryCode: '51', - signUpFields: [ - { - key: 'z', - label: 'Z', - required: true, - }, - { - key: 'username', - label: 'NEW USERNAME LABEL', - required: true, - } - ] - } - }); - - let phoneField = wrapper.find(PhoneField).at(0); - expect(phoneField.props().defaultDialCode).toEqual('+51'); - }); - - test('signUp should not complete if required field is not filled out', async () => { - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme, - signUpConfig: { - defaultCountryCode: '51', - signUpFields: [ - { - key: 'z', - label: 'Z', - required: true, - }, - { - key: 'username', - label: 'NEW USERNAME LABEL', - required: true, - } - ] - } - }); - - const spyon = jest.spyOn(Auth, 'signUp') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res(mockResult); - }); - }); - - const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - } - const event_password = { - target: { - name: 'password', - value: 'abc' - } - } - - const event_email = { - target: { - name: 'email', - value: 'email@amazon.com' - } - } - const event_phone = { - target: { - name: 'phone_line_number', - value: '2345678999' - } - } - const dial_code = { - target: { - name: 'dial_code', - value: '+1' - } - } - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - wrapper.find(Input).at(2).simulate('change', event_email); - wrapper.find(Input).at(3).simulate('change', event_phone); - await wrapper.find(Button).simulate('click'); - - - expect(spyon).not.toBeCalled(); - - }); - - test('signUp should complete if optional field is not filled out', async () => { - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme, - signUpConfig: { - defaultCountryCode: '51', - signUpFields: [ - { - key: 'z', - label: 'Z', - required: false, - }, - { - key: 'username', - label: 'NEW USERNAME LABEL', - required: true, - } - ] - } - }); - - const spyon = jest.spyOn(Auth, 'signUp') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res(mockResult); - }); - }); - - const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - } - const event_password = { - target: { - name: 'password', - value: 'abc' - } - } - - const event_email = { - target: { - name: 'email', - value: 'email@amazon.com' - } - } - const phone_number = '+12345678999'; - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - wrapper.find(Input).at(2).simulate('change', event_email); - wrapper.find(PhoneField).at(0).simulate('changeText', phone_number); - await wrapper.find(Button).simulate('click'); - - - expect(spyon).toBeCalled(); - - }); - - test('signUp should complete if required field is filled out', async () => { - wrapper.setProps({ - authState: 'signUp', - theme: AmplifyTheme, - signUpConfig: { - defaultCountryCode: '51', - signUpFields: [ - { - key: 'z', - label: 'Z', - required: true, - }, - { - key: 'username', - label: 'NEW USERNAME LABEL', - required: true, - } - ] - } - }); - - const spyon = jest.spyOn(Auth, 'signUp') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res(mockResult); - }); - }); - - const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - } - const event_password = { - target: { - name: 'password', - value: 'abc' - } - } - - const event_email = { - target: { - name: 'email', - value: 'email@amazon.com' - } - } - const phone_number = '+12345678999'; - const event_z = { - target: { - name: 'z', - value: '1' - } - } - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - wrapper.find(Input).at(2).simulate('change', event_email); - wrapper.find(PhoneField).at(0).simulate('changeText', phone_number); - wrapper.find(Input).at(3).simulate('change', event_z); - await wrapper.find(Button).simulate('click'); - - expect(spyon).toBeCalled(); - - }); - - test('signUp should complete even if phone field is hidden', async () => { - wrapper.setProps({ - authState: 'signUp', - signUpConfig: { - hiddenDefaults: ["phone_number"] - } - }); - - const spyon = jest.spyOn(Auth, 'signUp') - .mockImplementationOnce((user, password) => { - return new Promise((res, rej) => { - res(mockResult); - }); - }); - - const event_username = { - target: { - name: 'username', - value: 'user1' - } - } - - const event_password = { - target: { - name: 'password', - value: 'abc' - } - } - - const event_email = { - target: { - name: 'email', - value: 'email@amazon.com' - } - } - - wrapper.find(Input).at(0).simulate('change', event_username); - wrapper.find(Input).at(1).simulate('change', event_password); - wrapper.find(Input).at(2).simulate('change', event_email); - await wrapper.find(Button).simulate('click'); - - expect(spyon).toBeCalled(); - }); + let wrapper; + beforeEach(() => { + wrapper = shallow(); + }); + + test('render correctly with authState signUp', () => { + for (var i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + signUpConfig: { + signUpFields: [ + { + key: 'address', + label: 'Address', + required: true, + }, + ], + }, + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('render correctly with hide', () => { + for (var i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + hide: [SignUp], + signUpConfig: { + signUpFields: [ + { + key: 'address', + label: 'Address', + required: true, + }, + ], + }, + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('expect custom field to be last if display order not defined', () => { + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + signUpConfig: { + signUpFields: [ + { + key: 'address', + label: 'Address', + required: true, + }, + ], + }, + }); + const addressElementFound = wrapper.find({ name: 'address' }); + const addressChildFound = wrapper.find(Input).at(3); + expect(addressElementFound.props().name).toEqual( + addressChildFound.props().name + ); + }); + + test('expect custom field to be first if display order is defined as 1, and it is prior to username alpabetically', () => { + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + signUpConfig: { + signUpFields: [ + { + key: 'address', + label: 'Address', + required: true, + displayOrder: 1, + }, + ], + }, + }); + const addressElementFound = wrapper.find({ name: 'address' }); + const addressChildFound = wrapper.find(Input).at(0); + expect(addressElementFound.props().name).toEqual( + addressChildFound.props().name + ); + }); + + test('expect custom field to be second if display order is defined as 1, and it is after username alpabetically', () => { + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + signUpConfig: { + signUpFields: [ + { + key: 'z', + label: 'Z', + required: true, + displayOrder: 1, + }, + ], + }, + }); + const addressElementFound = wrapper.find({ name: 'z' }); + const addressChildFound = wrapper.find(Input).at(1); + expect(addressElementFound.props().name).toEqual( + addressChildFound.props().name + ); + }); + + test('expect 5 fields to be present if hideAllDefaults is undefined', () => { + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + signUpConfig: { + signUpFields: [ + { + key: 'z', + label: 'Z', + required: true, + displayOrder: 1, + }, + ], + }, + }); + expect(wrapper.find(Input).length).toEqual(4); + expect(wrapper.find(PhoneField).length).toEqual(1); + }); + + test('expect 5 fields to be present if hideAllDefaults is false', () => { + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + signUpConfig: { + hideAllDefaults: false, + signUpFields: [ + { + key: 'z', + label: 'Z', + required: true, + displayOrder: 1, + }, + ], + }, + }); + expect(wrapper.find(Input).length).toEqual(4); + expect(wrapper.find(PhoneField).length).toEqual(1); + }); + + test('expect custom field to be the only field if hideAllDefaults is true', () => { + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + signUpConfig: { + hideAllDefaults: true, + signUpFields: [ + { + key: 'z', + label: 'Z', + required: true, + displayOrder: 1, + }, + ], + }, + }); + expect(wrapper.find(Input).length).toEqual(1); + }); + + test('expect default username to be overwritten if username field passed in via signUpConfig', () => { + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + signUpConfig: { + signUpFields: [ + { + key: 'z', + label: 'Z', + required: true, + }, + { + key: 'username', + label: 'NEW USERNAME LABEL', + required: true, + }, + ], + }, + }); + + const signup = new SignUp(); + const defaultUsernameLabel = signup.defaultSignUpFields.find(i => { + return i.key === 'username'; + }).label; + + const customUsername = wrapper.find(InputLabel).findWhere(el => { + return el.text() === 'NEW USERNAME LABEL'; + }); + + const originalUsername = wrapper.find(InputLabel).findWhere(el => { + return el.text() === defaultUsernameLabel; + }); + + expect(customUsername.length).toEqual(1); + expect(originalUsername.length).toEqual(0); + }); + + test('default dial code should be set to passed defaultCountryCode', () => { + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + signUpConfig: { + defaultCountryCode: '51', + signUpFields: [ + { + key: 'z', + label: 'Z', + required: true, + }, + { + key: 'username', + label: 'NEW USERNAME LABEL', + required: true, + }, + ], + }, + }); + + let phoneField = wrapper.find(PhoneField).at(0); + expect(phoneField.props().defaultDialCode).toEqual('+51'); + }); + + test('signUp should not complete if required field is not filled out', async () => { + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + signUpConfig: { + defaultCountryCode: '51', + signUpFields: [ + { + key: 'z', + label: 'Z', + required: true, + }, + { + key: 'username', + label: 'NEW USERNAME LABEL', + required: true, + }, + ], + }, + }); + + const spyon = jest + .spyOn(Auth, 'signUp') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res(mockResult); + }); + }); + + const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + const event_email = { + target: { + name: 'email', + value: 'email@amazon.com', + }, + }; + const event_phone = { + target: { + name: 'phone_line_number', + value: '2345678999', + }, + }; + const dial_code = { + target: { + name: 'dial_code', + value: '+1', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + wrapper + .find(Input) + .at(2) + .simulate('change', event_email); + wrapper + .find(Input) + .at(3) + .simulate('change', event_phone); + await wrapper.find(Button).simulate('click'); + + expect(spyon).not.toBeCalled(); + }); + + test('signUp should complete if optional field is not filled out', async () => { + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + signUpConfig: { + defaultCountryCode: '51', + signUpFields: [ + { + key: 'z', + label: 'Z', + required: false, + }, + { + key: 'username', + label: 'NEW USERNAME LABEL', + required: true, + }, + ], + }, + }); + + const spyon = jest + .spyOn(Auth, 'signUp') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res(mockResult); + }); + }); + + const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + const event_email = { + target: { + name: 'email', + value: 'email@amazon.com', + }, + }; + const phone_number = '+12345678999'; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + wrapper + .find(Input) + .at(2) + .simulate('change', event_email); + wrapper + .find(PhoneField) + .at(0) + .simulate('changeText', phone_number); + await wrapper.find(Button).simulate('click'); + + expect(spyon).toBeCalled(); + }); + + test('signUp should complete if required field is filled out', async () => { + wrapper.setProps({ + authState: 'signUp', + theme: AmplifyTheme, + signUpConfig: { + defaultCountryCode: '51', + signUpFields: [ + { + key: 'z', + label: 'Z', + required: true, + }, + { + key: 'username', + label: 'NEW USERNAME LABEL', + required: true, + }, + ], + }, + }); + + const spyon = jest + .spyOn(Auth, 'signUp') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res(mockResult); + }); + }); + + const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState'); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + const event_email = { + target: { + name: 'email', + value: 'email@amazon.com', + }, + }; + const phone_number = '+12345678999'; + const event_z = { + target: { + name: 'z', + value: '1', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + wrapper + .find(Input) + .at(2) + .simulate('change', event_email); + wrapper + .find(PhoneField) + .at(0) + .simulate('changeText', phone_number); + wrapper + .find(Input) + .at(3) + .simulate('change', event_z); + await wrapper.find(Button).simulate('click'); + + expect(spyon).toBeCalled(); + }); + + test('signUp should complete even if phone field is hidden', async () => { + wrapper.setProps({ + authState: 'signUp', + signUpConfig: { + hiddenDefaults: ['phone_number'], + }, + }); + + const spyon = jest + .spyOn(Auth, 'signUp') + .mockImplementationOnce((user, password) => { + return new Promise((res, rej) => { + res(mockResult); + }); + }); + + const event_username = { + target: { + name: 'username', + value: 'user1', + }, + }; + + const event_password = { + target: { + name: 'password', + value: 'abc', + }, + }; + + const event_email = { + target: { + name: 'email', + value: 'email@amazon.com', + }, + }; + + wrapper + .find(Input) + .at(0) + .simulate('change', event_username); + wrapper + .find(Input) + .at(1) + .simulate('change', event_password); + wrapper + .find(Input) + .at(2) + .simulate('change', event_email); + await wrapper.find(Button).simulate('click'); + + expect(spyon).toBeCalled(); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/TOTPSetup-test.js b/packages/aws-amplify-react/__tests__/Auth/TOTPSetup-test.js index f5837637538..156abf74c16 100644 --- a/packages/aws-amplify-react/__tests__/Auth/TOTPSetup-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/TOTPSetup-test.js @@ -5,129 +5,134 @@ import AmplifyTheme from '../../src/AmplifyTheme'; import AuthPiece from '../../src/Auth/AuthPiece'; import { Header, Footer, InputRow, ButtonRow, Link } from '../../src/AmplifyUI'; -const acceptedStates = [ - 'TOTPSetup' -]; +const acceptedStates = ['TOTPSetup']; const deniedStates = [ - 'signIn', - 'signedUp', - 'signedOut', - 'signUp', - 'signedIn', - 'confirmSignUp', - 'forgotPassword', - 'verifyContact' + 'signIn', + 'signedUp', + 'signedOut', + 'signUp', + 'signedIn', + 'confirmSignUp', + 'forgotPassword', + 'verifyContact', ]; describe('TOTPSetup', () => { - describe('render test', () => { - test('render correctly', () => { - const wrapper = shallow(); - for (let i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('render hidden', () => { - const wrapper = shallow(); - - for (let i = 0; i < deniedStates.length; i += 1){ - wrapper.setProps({ - authState: deniedStates[i], - theme: AmplifyTheme - }); - - expect(wrapper).toMatchSnapshot(); - } - }); - - test('hide props', () => { - const wrapper = shallow(); - - for (let i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: AmplifyTheme - }); - expect(wrapper).toMatchSnapshot(); - } - }); - }); - - describe('onTOTPEvent test', () => { - test('happy case', () => { - const wrapper = shallow(); - const TOTPSetupInstance = wrapper.instance(); - - const spyon = jest.spyOn(TOTPSetupInstance, 'checkContact'); - TOTPSetupInstance.onTOTPEvent('Setup TOTP', 'SUCCESS', 'user'); - - expect(spyon).toBeCalledWith('user'); - spyon.mockClear(); - }); - - test('setup totp fail', () => { - const wrapper = shallow(); - const TOTPSetupInstance = wrapper.instance(); - - const spyon = jest.spyOn(TOTPSetupInstance, 'changeState'); - TOTPSetupInstance.onTOTPEvent('Setup TOTP', 'FAIL', 'user'); - - expect(spyon).not.toBeCalled(); - spyon.mockClear(); - }); - }); - - describe('checkContact test', () => { - test('contact verified', async () => { - const wrapper = shallow(); - const totpSetup = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'verifiedContact').mockImplementationOnce(() => { - return Promise.resolve({ - verified: { - email: 'xxx@xxx.com' - } - }); - }); - - const spyon2 = jest.spyOn(totpSetup, 'changeState'); - - await totpSetup.checkContact({ - user: 'user' - }); - - expect(spyon2).toBeCalledWith('signedIn', {user: 'user'}); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('contact not verified', async () => { - const wrapper = shallow(); - const totpSetup = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'verifiedContact').mockImplementationOnce(() => { - return Promise.resolve({ - verified: {} - }); - }); - - const spyon2 = jest.spyOn(totpSetup, 'changeState'); - - await totpSetup.checkContact({ - user: 'user' - }); - - expect(spyon2).toBeCalledWith('verifyContact', {user: 'user', 'verified': {}}); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); + describe('render test', () => { + test('render correctly', () => { + const wrapper = shallow(); + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('render hidden', () => { + const wrapper = shallow(); + + for (let i = 0; i < deniedStates.length; i += 1) { + wrapper.setProps({ + authState: deniedStates[i], + theme: AmplifyTheme, + }); + + expect(wrapper).toMatchSnapshot(); + } + }); + + test('hide props', () => { + const wrapper = shallow(); + + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: AmplifyTheme, + }); + expect(wrapper).toMatchSnapshot(); + } + }); + }); + + describe('onTOTPEvent test', () => { + test('happy case', () => { + const wrapper = shallow(); + const TOTPSetupInstance = wrapper.instance(); + + const spyon = jest.spyOn(TOTPSetupInstance, 'checkContact'); + TOTPSetupInstance.onTOTPEvent('Setup TOTP', 'SUCCESS', 'user'); + + expect(spyon).toBeCalledWith('user'); + spyon.mockClear(); + }); + + test('setup totp fail', () => { + const wrapper = shallow(); + const TOTPSetupInstance = wrapper.instance(); + + const spyon = jest.spyOn(TOTPSetupInstance, 'changeState'); + TOTPSetupInstance.onTOTPEvent('Setup TOTP', 'FAIL', 'user'); + + expect(spyon).not.toBeCalled(); + spyon.mockClear(); + }); + }); + + describe('checkContact test', () => { + test('contact verified', async () => { + const wrapper = shallow(); + const totpSetup = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'verifiedContact') + .mockImplementationOnce(() => { + return Promise.resolve({ + verified: { + email: 'xxx@xxx.com', + }, + }); + }); + + const spyon2 = jest.spyOn(totpSetup, 'changeState'); + + await totpSetup.checkContact({ + user: 'user', + }); + + expect(spyon2).toBeCalledWith('signedIn', { user: 'user' }); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('contact not verified', async () => { + const wrapper = shallow(); + const totpSetup = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'verifiedContact') + .mockImplementationOnce(() => { + return Promise.resolve({ + verified: {}, + }); + }); + + const spyon2 = jest.spyOn(totpSetup, 'changeState'); + + await totpSetup.checkContact({ + user: 'user', + }); + + expect(spyon2).toBeCalledWith('verifyContact', { + user: 'user', + verified: {}, + }); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/VerifyContact-test.js b/packages/aws-amplify-react/__tests__/Auth/VerifyContact-test.js index a956fae3459..332ffae47b2 100644 --- a/packages/aws-amplify-react/__tests__/Auth/VerifyContact-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/VerifyContact-test.js @@ -5,259 +5,282 @@ import AmplifyTheme from '../../src/AmplifyTheme'; import AuthPiece from '../../src/Auth/AuthPiece'; import { Button, Link } from '../../src/Amplify-UI/Amplify-UI-Components-React'; -const acceptedStates = [ - 'verifyContact' -]; +const acceptedStates = ['verifyContact']; const deniedStates = [ - 'signIn', - 'signedUp', - 'signedOut', - 'forgotPassword', - 'signedIn', - 'confirmSignIn', - 'confirmSignUp', - 'signUp' + 'signIn', + 'signedUp', + 'signedOut', + 'forgotPassword', + 'signedIn', + 'confirmSignIn', + 'confirmSignUp', + 'signUp', ]; describe.only('VerifyContent test', () => { - describe('render test', () => { - test('render with accepted states', () => { - const wrapper = shallow(); - for (let i = 0; i < acceptedStates.length; i += 1){ - wrapper.setProps({ - authState: acceptedStates[i], - theme: 'theme', - authData: { - unverified: { - email: 'email@amazon.com', - phone_number: '+12345678901' - } - } - }); - expect(wrapper).toMatchSnapshot(); - } - }); - - test('render submitView if verifyAttr is set', () => { - const wrapper = shallow(); - const props = { - authState: 'verifyContact', - theme: 'theme' - }; - wrapper.setProps(props); - wrapper.setState({ verifyAttr: true }); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render verifyView with empty authData', () => { - const wrapper = shallow(); - const props = { - authState: 'verifyContact', - theme: 'theme', - authData: {} - }; - wrapper.setProps(props); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render verifyView without phone_number and email', () => { - const wrapper = shallow(); - const props = { - authState: 'verifyContact', - theme: 'theme', - authData: { - unverified: {} - } - }; - wrapper.setProps(props); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render null with denied states', () => { - const wrapper = shallow(); - - for (let i = 0; i < deniedStates.length; i += 1){ - wrapper.setProps({ - authState: deniedStates[i], - theme: 'theme' - }); - - expect(wrapper).toMatchSnapshot(); - } - }); - - test('hidden', () => { - const wrapper = shallow(); - const props = { - authState: 'verifyContact', - theme: 'theme', - hide: [VerifyContact] - }; - wrapper.setProps(props); - - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('interaction test', () => { - test('Link clicked', () => { - const spyon = jest.spyOn(VerifyContact.prototype, 'changeState').mockImplementationOnce(() => { - return; - }); - const wrapper = shallow(); - const props = { - authState: 'verifyContact', - theme: 'theme' - }; - wrapper.setProps(props); - - wrapper.find(Link).simulate('click'); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - - test('verifyView ButonRow clicked', () => { - const spyon = jest.spyOn(VerifyContact.prototype, 'verify').mockImplementationOnce(() => { - return; - }); - const wrapper = shallow(); - const props = { - authState: 'verifyContact', - theme: 'theme', - authData: { - unverified: { - email: 'email@amazon.com', - phone_number: '+12345678901' - } - } - }; - wrapper.setProps(props); - - wrapper.find(Button).at(0).simulate('click'); - - // expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - }); - - describe('verify test', () => { - test('happy case', async () => { - const spyon = jest.spyOn(Auth, 'verifyCurrentUserAttribute').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - const wrapper = shallow(); - const verifyContact = wrapper.instance(); - verifyContact.inputs = { - contact: true, - checkedValue: 'email' - }; - - await verifyContact.verify(); - expect(spyon).toBeCalledWith('email'); - - spyon.mockClear(); - }); - - test('no cantact', async () => { - const spyon = jest.spyOn(VerifyContact.prototype, 'error').mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - const verifyContact = wrapper.instance(); - verifyContact.inputs = { - contact: null - }; - - await verifyContact.verify(); - expect(spyon).toBeCalledWith('Neither Email nor Phone Number selected'); - - spyon.mockClear(); - }); - - test('auth error', async () => { - const spyon = jest.spyOn(Auth, 'verifyCurrentUserAttribute').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - const spyon2 = jest.spyOn(VerifyContact.prototype, 'error').mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - const verifyContact = wrapper.instance(); - verifyContact.inputs = { - contact: 'contact' - }; - - await verifyContact.verify(); - expect(wrapper.state('verifyAttr')).toBeNull(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); - - describe('submit test', () => { - test('happy case', async () => { - const spyon = jest.spyOn(Auth, 'verifyCurrentUserAttributeSubmit').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - const spyon2 = jest.spyOn(VerifyContact.prototype, 'changeState').mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - const verifyContact = wrapper.instance(); - wrapper.setState({ verifyAttr: 'attr' }); - verifyContact.inputs = { - code: 'code' - }; - - await verifyContact.submit(); - expect(spyon).toBeCalledWith('attr', 'code'); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('auth error', async () => { - const spyon = jest.spyOn(Auth, 'verifyCurrentUserAttributeSubmit').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - const spyon2 = jest.spyOn(VerifyContact.prototype, 'error').mockImplementationOnce(() => { - return; - }); - const spyon3 = jest.spyOn(VerifyContact.prototype, 'changeState').mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - const verifyContact = wrapper.instance(); - verifyContact.inputs = { - code: 'code' - }; - - await verifyContact.submit(); - expect(spyon3).not.toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - }); - }); + describe('render test', () => { + test('render with accepted states', () => { + const wrapper = shallow(); + for (let i = 0; i < acceptedStates.length; i += 1) { + wrapper.setProps({ + authState: acceptedStates[i], + theme: 'theme', + authData: { + unverified: { + email: 'email@amazon.com', + phone_number: '+12345678901', + }, + }, + }); + expect(wrapper).toMatchSnapshot(); + } + }); + + test('render submitView if verifyAttr is set', () => { + const wrapper = shallow(); + const props = { + authState: 'verifyContact', + theme: 'theme', + }; + wrapper.setProps(props); + wrapper.setState({ verifyAttr: true }); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render verifyView with empty authData', () => { + const wrapper = shallow(); + const props = { + authState: 'verifyContact', + theme: 'theme', + authData: {}, + }; + wrapper.setProps(props); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render verifyView without phone_number and email', () => { + const wrapper = shallow(); + const props = { + authState: 'verifyContact', + theme: 'theme', + authData: { + unverified: {}, + }, + }; + wrapper.setProps(props); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render null with denied states', () => { + const wrapper = shallow(); + + for (let i = 0; i < deniedStates.length; i += 1) { + wrapper.setProps({ + authState: deniedStates[i], + theme: 'theme', + }); + + expect(wrapper).toMatchSnapshot(); + } + }); + + test('hidden', () => { + const wrapper = shallow(); + const props = { + authState: 'verifyContact', + theme: 'theme', + hide: [VerifyContact], + }; + wrapper.setProps(props); + + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('interaction test', () => { + test('Link clicked', () => { + const spyon = jest + .spyOn(VerifyContact.prototype, 'changeState') + .mockImplementationOnce(() => { + return; + }); + const wrapper = shallow(); + const props = { + authState: 'verifyContact', + theme: 'theme', + }; + wrapper.setProps(props); + + wrapper.find(Link).simulate('click'); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + + test('verifyView ButonRow clicked', () => { + const spyon = jest + .spyOn(VerifyContact.prototype, 'verify') + .mockImplementationOnce(() => { + return; + }); + const wrapper = shallow(); + const props = { + authState: 'verifyContact', + theme: 'theme', + authData: { + unverified: { + email: 'email@amazon.com', + phone_number: '+12345678901', + }, + }, + }; + wrapper.setProps(props); + + wrapper + .find(Button) + .at(0) + .simulate('click'); + + // expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + }); + + describe('verify test', () => { + test('happy case', async () => { + const spyon = jest + .spyOn(Auth, 'verifyCurrentUserAttribute') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + const wrapper = shallow(); + const verifyContact = wrapper.instance(); + verifyContact.inputs = { + contact: true, + checkedValue: 'email', + }; + + await verifyContact.verify(); + expect(spyon).toBeCalledWith('email'); + + spyon.mockClear(); + }); + + test('no cantact', async () => { + const spyon = jest + .spyOn(VerifyContact.prototype, 'error') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const verifyContact = wrapper.instance(); + verifyContact.inputs = { + contact: null, + }; + + await verifyContact.verify(); + expect(spyon).toBeCalledWith('Neither Email nor Phone Number selected'); + + spyon.mockClear(); + }); + + test('auth error', async () => { + const spyon = jest + .spyOn(Auth, 'verifyCurrentUserAttribute') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + const spyon2 = jest + .spyOn(VerifyContact.prototype, 'error') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const verifyContact = wrapper.instance(); + verifyContact.inputs = { + contact: 'contact', + }; + + await verifyContact.verify(); + expect(wrapper.state('verifyAttr')).toBeNull(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); + + describe('submit test', () => { + test('happy case', async () => { + const spyon = jest + .spyOn(Auth, 'verifyCurrentUserAttributeSubmit') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + const spyon2 = jest + .spyOn(VerifyContact.prototype, 'changeState') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const verifyContact = wrapper.instance(); + wrapper.setState({ verifyAttr: 'attr' }); + verifyContact.inputs = { + code: 'code', + }; + + await verifyContact.submit(); + expect(spyon).toBeCalledWith('attr', 'code'); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('auth error', async () => { + const spyon = jest + .spyOn(Auth, 'verifyCurrentUserAttributeSubmit') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + const spyon2 = jest + .spyOn(VerifyContact.prototype, 'error') + .mockImplementationOnce(() => { + return; + }); + const spyon3 = jest + .spyOn(VerifyContact.prototype, 'changeState') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const verifyContact = wrapper.instance(); + verifyContact.inputs = { + code: 'code', + }; + + await verifyContact.submit(); + expect(spyon3).not.toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Auth/index-test.js b/packages/aws-amplify-react/__tests__/Auth/index-test.js index 9934f53ab5d..7b3a8acb05f 100644 --- a/packages/aws-amplify-react/__tests__/Auth/index-test.js +++ b/packages/aws-amplify-react/__tests__/Auth/index-test.js @@ -3,38 +3,38 @@ import * as React from 'react'; import { Component } from 'react'; describe('hoc tests', () => { - describe('withAuthenticator test', () => { - test('when signed in', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const CompWithAuth = withAuthenticator(MockComp); - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); + describe('withAuthenticator test', () => { + test('when signed in', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const CompWithAuth = withAuthenticator(MockComp); + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); - test('when not signed in', () => { - const MockComp = class extends Component { - render() { - return
; - } - }; - const CompWithAuth = withAuthenticator(MockComp); - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - }); + test('when not signed in', () => { + const MockComp = class extends Component { + render() { + return
; + } + }; + const CompWithAuth = withAuthenticator(MockComp); + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); + }); }); describe('AuthenticatorWrapper test', () => { - describe('render test', () => { - test('render correctly', () => { - const mockfn = jest.fn(); - const wrapper = shallow(); + describe('render test', () => { + test('render correctly', () => { + const mockfn = jest.fn(); + const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - }); + expect(wrapper).toMatchSnapshot(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Storage/Common-test.js b/packages/aws-amplify-react/__tests__/Storage/Common-test.js index 9174eab3ef0..da71c7efe16 100644 --- a/packages/aws-amplify-react/__tests__/Storage/Common-test.js +++ b/packages/aws-amplify-react/__tests__/Storage/Common-test.js @@ -1,49 +1,49 @@ import { calcKey } from '../../src/Storage/Common'; -window.encodeURI = (name) => { - return name; +window.encodeURI = name => { + return name; }; describe('Storage Common test', () => { - describe('calcKey test', () => { - const file = { - name: 'name', - size: 'size', - type: 'type' - }; - - test('happy case when fileToKey is a string', () => { - expect(calcKey(file, 'fileToKey')).toBe('fileToKey'); - }); - - test('happy case when fileToKey is a function', () => { - const mockFn = jest.fn().mockImplementation((obj) => { - let str = ''; - for (const k in obj) { - str += obj[k] + ' '; - } - return str; - }); - - expect(calcKey(file, mockFn)).toBe('name_size_type_'); - }); - - test('happy case when fileToKey is a object', () => { - const fileToKey = {attr: 'attr'}; - - expect(calcKey(file, fileToKey)).toBe('{\"attr\":\"attr\"}'); - }); - - test('key is empty', () => { - const mockFn = jest.fn().mockImplementation((obj) => { - return null; - }); - - expect(calcKey(file, mockFn)).toBe('empty_key'); - }); - - test('fileToKey is empty', () => { - expect(calcKey(file, null)).toBe('name'); - }); - }); + describe('calcKey test', () => { + const file = { + name: 'name', + size: 'size', + type: 'type', + }; + + test('happy case when fileToKey is a string', () => { + expect(calcKey(file, 'fileToKey')).toBe('fileToKey'); + }); + + test('happy case when fileToKey is a function', () => { + const mockFn = jest.fn().mockImplementation(obj => { + let str = ''; + for (const k in obj) { + str += obj[k] + ' '; + } + return str; + }); + + expect(calcKey(file, mockFn)).toBe('name_size_type_'); + }); + + test('happy case when fileToKey is a object', () => { + const fileToKey = { attr: 'attr' }; + + expect(calcKey(file, fileToKey)).toBe('{"attr":"attr"}'); + }); + + test('key is empty', () => { + const mockFn = jest.fn().mockImplementation(obj => { + return null; + }); + + expect(calcKey(file, mockFn)).toBe('empty_key'); + }); + + test('fileToKey is empty', () => { + expect(calcKey(file, null)).toBe('name'); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Storage/S3Album-test.js b/packages/aws-amplify-react/__tests__/Storage/S3Album-test.js index b26b840e264..9a4a7afa495 100644 --- a/packages/aws-amplify-react/__tests__/Storage/S3Album-test.js +++ b/packages/aws-amplify-react/__tests__/Storage/S3Album-test.js @@ -6,482 +6,563 @@ import * as React from 'react'; import { JS } from '@aws-amplify/core'; const timespy = jest.spyOn(Date.prototype, 'getTime').mockImplementation(() => { - return 0; + return 0; }); describe('S3Album test', () => { - describe('render test', () => { - test('render correctly if has images and texts', () => { - const wrapper = shallow(); - - wrapper.setState({items: [{ - path: 'path', - key: 'imageKey', - contentType: 'application/json' - }, - { - path: 'path', - key: 'textKey', - contentType: 'image' - }]}); - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('interaction test', () => { - test('S3Text onclick', () => { - const spyon = jest.spyOn(S3Album.prototype, 'handleClick') - .mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - - wrapper.setState({items: [{ - path: 'path', - key: 'imageKey', - contentType: 'application/json' - }, - { - path: 'path', - key: 'textKey', - contentType: 'image' - }]}); - - wrapper.find(S3Text).simulate('click'); - - expect(spyon).toBeCalledWith({ - path: 'path', - key: 'imageKey', - contentType: 'application/json' - }); - - spyon.mockClear(); - }); - - test('S3Image onclick', () => { - const spyon = jest.spyOn(S3Album.prototype, 'handleClick') - .mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - - wrapper.setState({items: [{ - path: 'path', - key: 'imageKey', - contentType: 'application/json' - }, - { - path: 'path', - key: 'textKey', - contentType: 'image' - }]}); - - wrapper.find(S3Image).simulate('click'); - - expect(spyon).toBeCalledWith({ - path: 'path', - key: 'textKey', - contentType: 'image' - }); - - spyon.mockClear(); - }); - }); - - describe('getKey test', () => { - test('happy case with string type', () => { - const props = { - fileToKey: 'fileToKey' - }; - - const wrapper = shallow(); - const s3Album = wrapper.instance(); - wrapper.setProps(props); - - const file = { - name: 'name', - size: 'size', - type: 'type' - }; - - expect(s3Album.getKey(file)).toBe('fileToKey'); - }); - - test('happy case with function type', () => { - const mockFn = jest.fn(); - - const props = { - fileToKey: mockFn - }; - - const wrapper = shallow(); - const s3Album = wrapper.instance(); - wrapper.setProps(props); - - const file = { - name: 'name', - size: 'size', - type: 'type' - }; - - s3Album.getKey(file); - - expect(mockFn).toBeCalledWith({ - name: 'name', - size: 'size', - type: 'type' - }); - }); - - test('happy case with object type', () => { - const props = { - fileToKey: { - attr: 'attr' - } - }; - - const wrapper = shallow(); - const s3Album = wrapper.instance(); - wrapper.setProps(props); - - const file = { - name: 'name', - size: 'size', - type: 'type' - }; - - expect(s3Album.getKey(file)).toBe("%7B%22attr%22:%22attr%22%7D"); - }); - }); - - describe('handlePick test', () => { - const onPick = jest.fn(); - const onLoad = jest.fn(); - const onError = jest.fn(); - - test('happy case with item updated', async () => { - const data = { - file: 'file', - name: 'name', - size: 'size', - type: 'type' - }; - - const spyon = jest.spyOn(S3Album.prototype, 'getKey') - .mockImplementationOnce(() => { return ''; }); - - const spyon2 = jest.spyOn(Storage, 'put') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - const props = { - onPick, - onLoad, - onError, - path: 'path' - }; - const state = { - items: [{key: 'path'}] - }; - - const wrapper = shallow(); - const s3Album = wrapper.instance(); - wrapper.setProps(props); - wrapper.setState(state); - - - await s3Album.handlePick(data); - - expect.assertions(2); - expect(spyon).toBeCalledWith({"file": "file", "name": "name", "size": "size", "type": "type"}); - expect(spyon2) - .toBeCalledWith('path', 'file',{"contentType": "type", "level": "public", "track": undefined}); - - spyon.mockClear(); - spyon2.mockClear(); - onPick.mockClear(); - onLoad.mockClear(); - onError.mockClear(); - }); - - test('happy case with no item updated', async () => { - const data = { - file: 'file', - name: 'name', - size: 'size', - type: 'type' - }; - - const spyon = jest.spyOn(S3Album.prototype, 'getKey') - .mockImplementationOnce(() => { return ''; }); - - const spyon2 = jest.spyOn(Storage, 'put') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - const spyon3 = jest.spyOn(S3Album.prototype, 'marshal') - .mockImplementationOnce(() => { return; }); - - const props = { - onPick, - onLoad, - onError, - path: 'path' - }; - - const state = { - items: [{key: 'path2'}] - }; - - const wrapper = shallow(); - const s3Album = wrapper.instance(); - wrapper.setProps(props); - wrapper.setState(state); - - await s3Album.handlePick(data); - - expect(spyon).toBeCalledWith({"file": "file", "name": "name", "size": "size", "type": "type"}); - expect(spyon2) - .toBeCalledWith('path', 'file', {"contentType": "type", "level": "public", "track": undefined}); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - onPick.mockClear(); - onLoad.mockClear(); - onError.mockClear(); - }); - - test('Storage put error', async () => { - const data = { - file: 'file', - name: 'name', - size: 'size', - type: 'type' - }; - - const spyon = jest.spyOn(S3Album.prototype, 'getKey') - .mockImplementationOnce(() => { return ''; }); - - const spyon2 = jest.spyOn(Storage, 'put') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - const props = { - onPick, - onLoad, - onError, - path: 'path' - }; - const state = { - items: [{key: 'path'}] - }; - - const wrapper = shallow(); - const s3Album = wrapper.instance(); - wrapper.setProps(props); - wrapper.setState(state); - - await s3Album.handlePick(data); - - expect.assertions(2); - expect(spyon).toBeCalledWith({"file": "file", "name": "name", "size": "size", "type": "type"}); - expect(spyon2) - .toBeCalledWith('path', 'file', {"contentType": "type", "level": "public", "track": undefined}); - - spyon.mockClear(); - spyon2.mockClear(); - onPick.mockClear(); - onLoad.mockClear(); - onError.mockClear(); - }); - }); - - describe('handleClick test', () => { - const onClickItem = jest.fn(); - const onSelect = jest.fn(); - - test('happy case', () => { - const wrapper = shallow(); - - wrapper.setState({items: [{ - path: 'path', - key: 'imageKey', - contentType: 'application/json' - }, - { - path: 'path', - key: 'textKey', - contentType: 'image' - }]}); - - wrapper.find(S3Text).simulate('click'); - - expect(onSelect).toBeCalledWith( - {"contentType": "application/json", "key": "imageKey", "path": "path", "selected": true}, - [{"contentType": "application/json", "key": "imageKey", "path": "path", "selected": true}] - ); - - onSelect.mockClear(); - }); - - test('no select props', () => { - const wrapper = shallow(); - - wrapper.setState({items: [{ - path: 'path', - key: 'imageKey', - contentType: 'application/json' - }, - { - path: 'path', - key: 'textKey', - contentType: 'image' - }]}); - - wrapper.find(S3Text).simulate('click'); - - expect(onSelect).not.toBeCalled(); - - onSelect.mockClear(); - }); - - test('no onselect func', () => { - const wrapper = shallow(); - - wrapper.setState({items: [{ - path: 'path', - key: 'imageKey', - contentType: 'application/json' - }, - { - path: 'path', - key: 'textKey', - contentType: 'image' - }]}); - - wrapper.find(S3Text).simulate('click'); - - expect(onSelect).not.toBeCalled(); - - onSelect.mockClear(); - }); - - onClickItem.mockClear(); - onSelect.mockClear(); - }); - - describe('list test', () => { - test('happy case', async () => { - // this is for component did mount - const spyon = jest.spyOn(Storage, 'list') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - const spyon2 = jest.spyOn(S3Album.prototype, 'marshal') - .mockImplementationOnce(() => { return; }); - - const props = { - path: 'path', - level: 'public', - identityId: 'identityId' - }; - - const wrapper = shallow(); - const s3Album = wrapper.instance(); - wrapper.setProps(props); - - const spyon3 = jest.spyOn(Storage, 'list') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - await s3Album.list(); - - expect(spyon3).toBeCalledWith('path', {level: 'public',identityId: 'identityId'}); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - }); - - test('storage list error', async () => { - const spyon = jest.spyOn(Storage, 'list') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - const props = { - path: 'path', - level: 'public' - }; - - const wrapper = shallow(); - const s3Album = wrapper.instance(); - wrapper.setProps(props); - - const spyon2 = jest.spyOn(Storage, 'list') - .mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - expect(await s3Album.list()).toEqual([]); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); - - describe('contentType test', () => { - test('happy case', () => { - const spyon = jest.spyOn(JS, 'filenameToContentType').mockReturnValueOnce(); - - const wrapper = shallow(); - const s3Album = wrapper.instance(); - - s3Album.contentType({ - key: 'key' - }); - - expect(spyon).toBeCalledWith('key', 'image/*'); - - spyon.mockClear(); - }); - }); - - describe('marshal test', () => { - test('happy case with contentType string', async () => { - const spyon = jest.spyOn(Storage, 'list').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res([{data: 'data', key: 'data-1'}]); - }); - }); - const wrapper = await mount(); - - expect(wrapper.state('items')).toEqual([{"contentType": "string", "data": "data", "key": "data-1"}]); - - spyon.mockClear(); - await wrapper.unmount(); - }); - - }); + describe('render test', () => { + test('render correctly if has images and texts', () => { + const wrapper = shallow(); + + wrapper.setState({ + items: [ + { + path: 'path', + key: 'imageKey', + contentType: 'application/json', + }, + { + path: 'path', + key: 'textKey', + contentType: 'image', + }, + ], + }); + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('interaction test', () => { + test('S3Text onclick', () => { + const spyon = jest + .spyOn(S3Album.prototype, 'handleClick') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + + wrapper.setState({ + items: [ + { + path: 'path', + key: 'imageKey', + contentType: 'application/json', + }, + { + path: 'path', + key: 'textKey', + contentType: 'image', + }, + ], + }); + + wrapper.find(S3Text).simulate('click'); + + expect(spyon).toBeCalledWith({ + path: 'path', + key: 'imageKey', + contentType: 'application/json', + }); + + spyon.mockClear(); + }); + + test('S3Image onclick', () => { + const spyon = jest + .spyOn(S3Album.prototype, 'handleClick') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + + wrapper.setState({ + items: [ + { + path: 'path', + key: 'imageKey', + contentType: 'application/json', + }, + { + path: 'path', + key: 'textKey', + contentType: 'image', + }, + ], + }); + + wrapper.find(S3Image).simulate('click'); + + expect(spyon).toBeCalledWith({ + path: 'path', + key: 'textKey', + contentType: 'image', + }); + + spyon.mockClear(); + }); + }); + + describe('getKey test', () => { + test('happy case with string type', () => { + const props = { + fileToKey: 'fileToKey', + }; + + const wrapper = shallow(); + const s3Album = wrapper.instance(); + wrapper.setProps(props); + + const file = { + name: 'name', + size: 'size', + type: 'type', + }; + + expect(s3Album.getKey(file)).toBe('fileToKey'); + }); + + test('happy case with function type', () => { + const mockFn = jest.fn(); + + const props = { + fileToKey: mockFn, + }; + + const wrapper = shallow(); + const s3Album = wrapper.instance(); + wrapper.setProps(props); + + const file = { + name: 'name', + size: 'size', + type: 'type', + }; + + s3Album.getKey(file); + + expect(mockFn).toBeCalledWith({ + name: 'name', + size: 'size', + type: 'type', + }); + }); + + test('happy case with object type', () => { + const props = { + fileToKey: { + attr: 'attr', + }, + }; + + const wrapper = shallow(); + const s3Album = wrapper.instance(); + wrapper.setProps(props); + + const file = { + name: 'name', + size: 'size', + type: 'type', + }; + + expect(s3Album.getKey(file)).toBe('%7B%22attr%22:%22attr%22%7D'); + }); + }); + + describe('handlePick test', () => { + const onPick = jest.fn(); + const onLoad = jest.fn(); + const onError = jest.fn(); + + test('happy case with item updated', async () => { + const data = { + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }; + + const spyon = jest + .spyOn(S3Album.prototype, 'getKey') + .mockImplementationOnce(() => { + return ''; + }); + + const spyon2 = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + const props = { + onPick, + onLoad, + onError, + path: 'path', + }; + const state = { + items: [{ key: 'path' }], + }; + + const wrapper = shallow(); + const s3Album = wrapper.instance(); + wrapper.setProps(props); + wrapper.setState(state); + + await s3Album.handlePick(data); + + expect.assertions(2); + expect(spyon).toBeCalledWith({ + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }); + expect(spyon2).toBeCalledWith('path', 'file', { + contentType: 'type', + level: 'public', + track: undefined, + }); + + spyon.mockClear(); + spyon2.mockClear(); + onPick.mockClear(); + onLoad.mockClear(); + onError.mockClear(); + }); + + test('happy case with no item updated', async () => { + const data = { + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }; + + const spyon = jest + .spyOn(S3Album.prototype, 'getKey') + .mockImplementationOnce(() => { + return ''; + }); + + const spyon2 = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + const spyon3 = jest + .spyOn(S3Album.prototype, 'marshal') + .mockImplementationOnce(() => { + return; + }); + + const props = { + onPick, + onLoad, + onError, + path: 'path', + }; + + const state = { + items: [{ key: 'path2' }], + }; + + const wrapper = shallow(); + const s3Album = wrapper.instance(); + wrapper.setProps(props); + wrapper.setState(state); + + await s3Album.handlePick(data); + + expect(spyon).toBeCalledWith({ + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }); + expect(spyon2).toBeCalledWith('path', 'file', { + contentType: 'type', + level: 'public', + track: undefined, + }); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + onPick.mockClear(); + onLoad.mockClear(); + onError.mockClear(); + }); + + test('Storage put error', async () => { + const data = { + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }; + + const spyon = jest + .spyOn(S3Album.prototype, 'getKey') + .mockImplementationOnce(() => { + return ''; + }); + + const spyon2 = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + const props = { + onPick, + onLoad, + onError, + path: 'path', + }; + const state = { + items: [{ key: 'path' }], + }; + + const wrapper = shallow(); + const s3Album = wrapper.instance(); + wrapper.setProps(props); + wrapper.setState(state); + + await s3Album.handlePick(data); + + expect.assertions(2); + expect(spyon).toBeCalledWith({ + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }); + expect(spyon2).toBeCalledWith('path', 'file', { + contentType: 'type', + level: 'public', + track: undefined, + }); + + spyon.mockClear(); + spyon2.mockClear(); + onPick.mockClear(); + onLoad.mockClear(); + onError.mockClear(); + }); + }); + + describe('handleClick test', () => { + const onClickItem = jest.fn(); + const onSelect = jest.fn(); + + test('happy case', () => { + const wrapper = shallow( + + ); + + wrapper.setState({ + items: [ + { + path: 'path', + key: 'imageKey', + contentType: 'application/json', + }, + { + path: 'path', + key: 'textKey', + contentType: 'image', + }, + ], + }); + + wrapper.find(S3Text).simulate('click'); + + expect(onSelect).toBeCalledWith( + { + contentType: 'application/json', + key: 'imageKey', + path: 'path', + selected: true, + }, + [ + { + contentType: 'application/json', + key: 'imageKey', + path: 'path', + selected: true, + }, + ] + ); + + onSelect.mockClear(); + }); + + test('no select props', () => { + const wrapper = shallow( + + ); + + wrapper.setState({ + items: [ + { + path: 'path', + key: 'imageKey', + contentType: 'application/json', + }, + { + path: 'path', + key: 'textKey', + contentType: 'image', + }, + ], + }); + + wrapper.find(S3Text).simulate('click'); + + expect(onSelect).not.toBeCalled(); + + onSelect.mockClear(); + }); + + test('no onselect func', () => { + const wrapper = shallow( + + ); + + wrapper.setState({ + items: [ + { + path: 'path', + key: 'imageKey', + contentType: 'application/json', + }, + { + path: 'path', + key: 'textKey', + contentType: 'image', + }, + ], + }); + + wrapper.find(S3Text).simulate('click'); + + expect(onSelect).not.toBeCalled(); + + onSelect.mockClear(); + }); + + onClickItem.mockClear(); + onSelect.mockClear(); + }); + + describe('list test', () => { + test('happy case', async () => { + // this is for component did mount + const spyon = jest.spyOn(Storage, 'list').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + const spyon2 = jest + .spyOn(S3Album.prototype, 'marshal') + .mockImplementationOnce(() => { + return; + }); + + const props = { + path: 'path', + level: 'public', + identityId: 'identityId', + }; + + const wrapper = shallow(); + const s3Album = wrapper.instance(); + wrapper.setProps(props); + + const spyon3 = jest.spyOn(Storage, 'list').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + await s3Album.list(); + + expect(spyon3).toBeCalledWith('path', { + level: 'public', + identityId: 'identityId', + }); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + }); + + test('storage list error', async () => { + const spyon = jest.spyOn(Storage, 'list').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + const props = { + path: 'path', + level: 'public', + }; + + const wrapper = shallow(); + const s3Album = wrapper.instance(); + wrapper.setProps(props); + + const spyon2 = jest.spyOn(Storage, 'list').mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + expect(await s3Album.list()).toEqual([]); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); + + describe('contentType test', () => { + test('happy case', () => { + const spyon = jest + .spyOn(JS, 'filenameToContentType') + .mockReturnValueOnce(); + + const wrapper = shallow(); + const s3Album = wrapper.instance(); + + s3Album.contentType({ + key: 'key', + }); + + expect(spyon).toBeCalledWith('key', 'image/*'); + + spyon.mockClear(); + }); + }); + + describe('marshal test', () => { + test('happy case with contentType string', async () => { + const spyon = jest.spyOn(Storage, 'list').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res([{ data: 'data', key: 'data-1' }]); + }); + }); + const wrapper = await mount(); + + expect(wrapper.state('items')).toEqual([ + { contentType: 'string', data: 'data', key: 'data-1' }, + ]); + + spyon.mockClear(); + await wrapper.unmount(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Storage/S3Image-test.js b/packages/aws-amplify-react/__tests__/Storage/S3Image-test.js index 50723aefaff..18bf82b3480 100644 --- a/packages/aws-amplify-react/__tests__/Storage/S3Image-test.js +++ b/packages/aws-amplify-react/__tests__/Storage/S3Image-test.js @@ -1,9 +1,9 @@ jest.mock('../../src/Storage/Common', () => { - const calcKey = () => { - return ''; - }; + const calcKey = () => { + return ''; + }; - return { calcKey }; + return { calcKey }; }); import Storage from '@aws-amplify/storage'; @@ -13,328 +13,348 @@ import { PhotoPicker } from '../../src/Widget'; import * as React from 'react'; describe('S3Image', () => { - describe('render test', () => { - test('render null if no test and no picker', () => { - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render with picker true', () => { - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render with src exist', () => { - const wrapper = shallow(); - wrapper.setState({src: 'imageSrc'}); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render with translate text', () => { - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('interaction test', () => { - test('PhotoPicker onPick test', () => { - const spyon = jest.spyOn(S3Image.prototype, 'handlePick') - .mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - - wrapper.find(PhotoPicker).simulate('pick'); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - - test('imageEl click test', () => { - const spyon = jest.spyOn(S3Image.prototype, 'handleClick') - .mockImplementationOnce(() => { - return; - }); - const wrapper = shallow(); - wrapper.setState({src: 'imageSrc'}); - - wrapper.find('div').at(1).simulate('click'); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - }); - - describe('load test', () => { - test('happy case with body set', async () => { - const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - const spyon2 = jest.spyOn(S3Image.prototype, 'getImageSource').mockImplementationOnce(() => { - return; - }); - - const props = { - imgKey: 'imgKey', - body: 'imgBody' - }; - - const wrapper = shallow(); - const s3Image = wrapper.instance(); - wrapper.setProps(props); - - await s3Image.load(); - - expect.assertions(2); - expect(spyon).toBeCalledWith('imgKey', 'imgBody', { contentType: 'binary/octet-stream', level: 'public' }); - expect(spyon2).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('nothing to do if no imgKey and path set', async () => { - const wrapper = shallow(); - const s3Image = wrapper.instance(); - - await s3Image.load(); - }); - - test('only get image source when body no specified', async () => { - const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('text'); - }); - }); - - const spyon2 = jest.spyOn(S3Image.prototype, 'getImageSource').mockImplementationOnce(() => { - return; - }); - - const props = { - imgKey: 'imgKey' - }; - - const wrapper = shallow(); - const s3Image = wrapper.instance(); - wrapper.setProps(props); - - await s3Image.load(); - - expect.assertions(2); - expect(spyon).not.toBeCalled(); - expect(spyon2).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); - - describe('handlePick test', () => { - test('happy case', async () => { - const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - const spyon2 = jest.spyOn(S3Image.prototype, 'getImageSource').mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - const s3Image = wrapper.instance(); - wrapper.setProps({ - imgKey: 'imgKey', - level: 'level', - fileToKey: 'fileToKey' - }); - - const data = { - file: 'file', - name: 'name', - size: 'size', - type: 'type' - }; - - await s3Image.handlePick(data); - - expect.assertions(2); - expect(spyon) - .toBeCalledWith('imgKey', 'file', {"contentType": "type", "level": "level", "track": undefined}); - expect(spyon2).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('storage put error', async () => { - const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - const wrapper = shallow(); - const s3Image = wrapper.instance(); - wrapper.setProps({ - imgKey: 'imgKey', - level: 'level', - fileToKey: 'fileToKey' - }); - - const data = { - file: 'file', - name: 'name', - size: 'size', - type: 'type' - }; - - await s3Image.handlePick(data); - - spyon.mockClear(); - }); - }); - - describe('handleClick test', () => { - test('happy case', () => { - const mockFn = jest.fn(); - const props = { - onClick: mockFn - }; - - const wrapper = shallow(); - const s3Image = wrapper.instance(); - wrapper.setProps(props); - - s3Image.handleClick('evt'); - - expect(mockFn).toBeCalledWith('evt'); - }); - - test('if no onclick', () => { - const mockFn = jest.fn(); - - const wrapper = shallow(); - const s3Image = wrapper.instance(); - - s3Image.handleClick('evt'); - }); - }); - - describe('handleOnLoad test', () => { - test('happy case', () => { - const mockFn = jest.fn(); - const props = { - onLoad: mockFn - }; - const state = { - src: 'src' - }; - const wrapper = shallow(); - const s3Image = wrapper.instance(); - wrapper.setProps(props); - wrapper.setState(state); - - s3Image.handleOnLoad('img'); - - expect(mockFn).toBeCalledWith('src'); - }); - - test('if no onLoad', () => { - const mockFn = jest.fn(); - - const wrapper = shallow(); - const s3Image = wrapper.instance(); - - - s3Image.handleOnLoad('evt'); - }); - }); - - describe('handleOnError test', () => { - test('happy case', () => { - const mockFn = jest.fn(); - const props = { - onError: mockFn - }; - const state = { - src: 'src' - }; - const wrapper = shallow(); - const s3Image = wrapper.instance(); - wrapper.setProps(props); - wrapper.setState(state); - - s3Image.handleOnError('err'); - - expect(mockFn).toBeCalledWith('src'); - }); - }); - - describe('ImageEl test', () => { - test('null text', () => { - const wrapper = shallow(); - const s3Image = wrapper.instance(); - - expect(s3Image.imageEl(null, 'theme')).toBeNull(); - }); - }); - - describe('componentDidmount test', () => { - test('happy case', () => { - const spyon = jest.spyOn(S3Image.prototype, 'load'); - - const wrapper = mount(); - - expect(spyon).toBeCalled(); - spyon.mockClear(); - }); - }); - - describe('getImageSource test', () => { - test('happy case', () => { - const wrapper = shallow(); - const s3Image = wrapper.instance(); - - const spyon = jest.spyOn(Storage, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('url'); - }); - }); - - s3Image.getImageSource('key', 'level', false, 'identityId'); - expect(spyon).toBeCalledWith('key', {level: 'level', track: false, identityId: 'identityId'}); - spyon.mockClear(); - }); - - test('error case', () => { - const wrapper = shallow(); - const s3Image = wrapper.instance(); - - const spyon = jest.spyOn(Storage, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - try { - s3Image.getImageSource('key', 'level', false); - } catch (e) { - expect(e).not.toBeNull(); - } - - spyon.mockClear(); - }); - }); + describe('render test', () => { + test('render null if no test and no picker', () => { + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render with picker true', () => { + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render with src exist', () => { + const wrapper = shallow(); + wrapper.setState({ src: 'imageSrc' }); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render with translate text', () => { + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('interaction test', () => { + test('PhotoPicker onPick test', () => { + const spyon = jest + .spyOn(S3Image.prototype, 'handlePick') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + + wrapper.find(PhotoPicker).simulate('pick'); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + + test('imageEl click test', () => { + const spyon = jest + .spyOn(S3Image.prototype, 'handleClick') + .mockImplementationOnce(() => { + return; + }); + const wrapper = shallow(); + wrapper.setState({ src: 'imageSrc' }); + + wrapper + .find('div') + .at(1) + .simulate('click'); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + }); + + describe('load test', () => { + test('happy case with body set', async () => { + const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + const spyon2 = jest + .spyOn(S3Image.prototype, 'getImageSource') + .mockImplementationOnce(() => { + return; + }); + + const props = { + imgKey: 'imgKey', + body: 'imgBody', + }; + + const wrapper = shallow(); + const s3Image = wrapper.instance(); + wrapper.setProps(props); + + await s3Image.load(); + + expect.assertions(2); + expect(spyon).toBeCalledWith('imgKey', 'imgBody', { + contentType: 'binary/octet-stream', + level: 'public', + }); + expect(spyon2).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('nothing to do if no imgKey and path set', async () => { + const wrapper = shallow(); + const s3Image = wrapper.instance(); + + await s3Image.load(); + }); + + test('only get image source when body no specified', async () => { + const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('text'); + }); + }); + + const spyon2 = jest + .spyOn(S3Image.prototype, 'getImageSource') + .mockImplementationOnce(() => { + return; + }); + + const props = { + imgKey: 'imgKey', + }; + + const wrapper = shallow(); + const s3Image = wrapper.instance(); + wrapper.setProps(props); + + await s3Image.load(); + + expect.assertions(2); + expect(spyon).not.toBeCalled(); + expect(spyon2).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); + + describe('handlePick test', () => { + test('happy case', async () => { + const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + const spyon2 = jest + .spyOn(S3Image.prototype, 'getImageSource') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const s3Image = wrapper.instance(); + wrapper.setProps({ + imgKey: 'imgKey', + level: 'level', + fileToKey: 'fileToKey', + }); + + const data = { + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }; + + await s3Image.handlePick(data); + + expect.assertions(2); + expect(spyon).toBeCalledWith('imgKey', 'file', { + contentType: 'type', + level: 'level', + track: undefined, + }); + expect(spyon2).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('storage put error', async () => { + const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + const wrapper = shallow(); + const s3Image = wrapper.instance(); + wrapper.setProps({ + imgKey: 'imgKey', + level: 'level', + fileToKey: 'fileToKey', + }); + + const data = { + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }; + + await s3Image.handlePick(data); + + spyon.mockClear(); + }); + }); + + describe('handleClick test', () => { + test('happy case', () => { + const mockFn = jest.fn(); + const props = { + onClick: mockFn, + }; + + const wrapper = shallow(); + const s3Image = wrapper.instance(); + wrapper.setProps(props); + + s3Image.handleClick('evt'); + + expect(mockFn).toBeCalledWith('evt'); + }); + + test('if no onclick', () => { + const mockFn = jest.fn(); + + const wrapper = shallow(); + const s3Image = wrapper.instance(); + + s3Image.handleClick('evt'); + }); + }); + + describe('handleOnLoad test', () => { + test('happy case', () => { + const mockFn = jest.fn(); + const props = { + onLoad: mockFn, + }; + const state = { + src: 'src', + }; + const wrapper = shallow(); + const s3Image = wrapper.instance(); + wrapper.setProps(props); + wrapper.setState(state); + + s3Image.handleOnLoad('img'); + + expect(mockFn).toBeCalledWith('src'); + }); + + test('if no onLoad', () => { + const mockFn = jest.fn(); + + const wrapper = shallow(); + const s3Image = wrapper.instance(); + + s3Image.handleOnLoad('evt'); + }); + }); + + describe('handleOnError test', () => { + test('happy case', () => { + const mockFn = jest.fn(); + const props = { + onError: mockFn, + }; + const state = { + src: 'src', + }; + const wrapper = shallow(); + const s3Image = wrapper.instance(); + wrapper.setProps(props); + wrapper.setState(state); + + s3Image.handleOnError('err'); + + expect(mockFn).toBeCalledWith('src'); + }); + }); + + describe('ImageEl test', () => { + test('null text', () => { + const wrapper = shallow(); + const s3Image = wrapper.instance(); + + expect(s3Image.imageEl(null, 'theme')).toBeNull(); + }); + }); + + describe('componentDidmount test', () => { + test('happy case', () => { + const spyon = jest.spyOn(S3Image.prototype, 'load'); + + const wrapper = mount(); + + expect(spyon).toBeCalled(); + spyon.mockClear(); + }); + }); + + describe('getImageSource test', () => { + test('happy case', () => { + const wrapper = shallow(); + const s3Image = wrapper.instance(); + + const spyon = jest.spyOn(Storage, 'get').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('url'); + }); + }); + + s3Image.getImageSource('key', 'level', false, 'identityId'); + expect(spyon).toBeCalledWith('key', { + level: 'level', + track: false, + identityId: 'identityId', + }); + spyon.mockClear(); + }); + + test('error case', () => { + const wrapper = shallow(); + const s3Image = wrapper.instance(); + + const spyon = jest.spyOn(Storage, 'get').mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + try { + s3Image.getImageSource('key', 'level', false); + } catch (e) { + expect(e).not.toBeNull(); + } + + spyon.mockClear(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Storage/S3Text-test.js b/packages/aws-amplify-react/__tests__/Storage/S3Text-test.js index cba190abb97..1e6364c88e0 100644 --- a/packages/aws-amplify-react/__tests__/Storage/S3Text-test.js +++ b/packages/aws-amplify-react/__tests__/Storage/S3Text-test.js @@ -1,9 +1,9 @@ jest.mock('../../src/Storage/Common', () => { - const calcKey = () => { - return ''; - }; + const calcKey = () => { + return ''; + }; - return { calcKey }; + return { calcKey }; }); import Storage from '@aws-amplify/storage'; import S3Text from '../../src/Storage/S3Text'; @@ -12,329 +12,351 @@ import { TextPicker } from '../../src/Widget'; import * as React from 'react'; describe('S3Text test', () => { - describe('render test', () => { - test('render null if no test and no picker', () => { - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render with picker true', () => { - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render with text exist', () => { - const wrapper = shallow(); - wrapper.setState({text: 'text'}); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render with translate text', () => { - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('interaction test', () => { - test('TextPicker onPick test', () => { - const spyon = jest.spyOn(S3Text.prototype, 'handlePick') - .mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - - wrapper.find(TextPicker).simulate('pick'); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - - test('textEl click test', () => { - const spyon = jest.spyOn(S3Text.prototype, 'handleClick') - .mockImplementationOnce(() => { - return; - }); - const wrapper = shallow(); - wrapper.setState({text: 'text'}); - - wrapper.find('div').at(1).simulate('click'); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - }); - - describe('load test', () => { - test('happy case with body set', async () => { - const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('text'); - }); - }); - const spyon2 = jest.spyOn(S3Text.prototype, 'getText').mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - const s3Text = wrapper.instance(); - wrapper.setProps({ - textKey: 'textKey', - body: 'textBody' - }); - - await s3Text.load(); - - expect.assertions(2); - expect(spyon).toBeCalledWith('textKey', 'textBody', { contentType: 'text/*', level: 'public' }); - expect(spyon2).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('nothing to do if no textKey and path set', async () => { - const wrapper = shallow(); - const s3Text = wrapper.instance(); - - await s3Text.load(); - }); - - test('only get text when body no specified', async () => { - const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('text'); - }); - }); - const spyon2 = jest.spyOn(S3Text.prototype, 'getText').mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - const s3Text = wrapper.instance(); - wrapper.setProps({ - textKey: 'textKey' - }); - - await s3Text.load(); - - expect.assertions(2); - expect(spyon).not.toBeCalled(); - expect(spyon2).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - }); - - describe('handlePick test', () => { - test('happy case', async () => { - const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - const spyon2 = jest.spyOn(S3Text.prototype, 'getText').mockImplementationOnce(() => { - return; - }); - - const wrapper = shallow(); - const s3Text = wrapper.instance(); - wrapper.setProps({ - text: 'text', - textKey: 'textKey', - level: 'level', - fileToKey: 'fileToKey' - }); - - const data = { - file: 'file', - name: 'name', - size: 'size', - type: 'type' - }; - - await s3Text.handlePick(data); - - expect.assertions(2); - expect(spyon) - .toBeCalledWith('textKey', 'file', {"contentType": "type", "level": "level", "track": undefined}); - expect(spyon2).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - }); - - test('storage put error', async () => { - const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - const wrapper = shallow(); - const s3Text = wrapper.instance(); - wrapper.setProps({ - text: 'text', - textKey: 'textKey', - level: 'level', - fileToKey: 'fileToKey' - }); - - const data = { - file: 'file', - name: 'name', - size: 'size', - type: 'type' - }; - - await s3Text.handlePick(data); - - spyon.mockClear(); - }); - }); - - describe('handleClick test', () => { - test('happy case', () => { - const mockFn = jest.fn(); - const props = { - text: 'text', - textKey: 'textKey', - onClick: mockFn - }; - - const wrapper = shallow(); - const s3Text = wrapper.instance(); - wrapper.setProps(props); - - s3Text.handleClick('evt'); - - expect(mockFn).toBeCalledWith('evt'); - }); - - test('if no onclick', () => { - const mockFn = jest.fn(); - const props = { - text: 'text', - textKey: 'textKey' - }; - const wrapper = shallow(); - const s3Text = wrapper.instance(); - wrapper.setProps(props); - - s3Text.handleClick('evt'); - }); - }); - - describe('handleOnLoad test', () => { - test('happy case', () => { - const mockFn = jest.fn(); - const props = { - text: 'text', - textKey: 'textKey', - onLoad: mockFn - }; - const wrapper = shallow(); - const s3Text = wrapper.instance(); - wrapper.setProps(props); - - s3Text.handleOnLoad('text'); - - expect(mockFn).toBeCalledWith('text'); - }); - - test('if no onLoad', () => { - const mockFn = jest.fn(); - const props = { - text: 'text', - textKey: 'textKey' - }; - const wrapper = shallow(); - const s3Text = wrapper.instance(); - wrapper.setProps(props); - - s3Text.handleOnLoad('evt'); - }); - }); - - describe('handleOnError test', () => { - test('happy case', () => { - const mockFn = jest.fn(); - const props = { - text: 'text', - textKey: 'textKey', - onError: mockFn - }; - const wrapper = shallow(); - const s3Text = wrapper.instance(); - wrapper.setProps(props); - - s3Text.handleOnError('err'); - - expect(mockFn).toBeCalledWith('err'); - }); - }); - - describe('textEl test', () => { - test('null text', () => { - const wrapper = shallow(); - const s3Text = wrapper.instance(); - - expect(s3Text.textEl(null, 'theme')).toBeNull(); - }); - }); - - describe('componentDidmount test', () => { - test('happy case', () => { - const spyon = jest.spyOn(S3Text.prototype, 'load'); - - const wrapper = mount(); - - expect(spyon).toBeCalled(); - spyon.mockClear(); - }); - }); - - describe('getText test', () => { - test('happy case', () => { - const wrapper = shallow(); - const s3Text = wrapper.instance(); - - const spyon = jest.spyOn(Storage, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('url'); - }); - }); - - s3Text.getText('key', 'level', false, 'identityId'); - expect(spyon).toBeCalledWith('key', {"download": true, "level": "level", "track": false, identityId: 'identityId'}); - spyon.mockClear(); - }); - - test('error case', () => { - const wrapper = shallow(); - const s3Text = wrapper.instance(); - - const spyon = jest.spyOn(Storage, 'get').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - try { - s3Text.getText('key', 'level', false); - } catch (e) { - expect(e).not.toBeNull(); - } - - spyon.mockClear(); - }); - }); + describe('render test', () => { + test('render null if no test and no picker', () => { + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render with picker true', () => { + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render with text exist', () => { + const wrapper = shallow(); + wrapper.setState({ text: 'text' }); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render with translate text', () => { + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('interaction test', () => { + test('TextPicker onPick test', () => { + const spyon = jest + .spyOn(S3Text.prototype, 'handlePick') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + + wrapper.find(TextPicker).simulate('pick'); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + + test('textEl click test', () => { + const spyon = jest + .spyOn(S3Text.prototype, 'handleClick') + .mockImplementationOnce(() => { + return; + }); + const wrapper = shallow(); + wrapper.setState({ text: 'text' }); + + wrapper + .find('div') + .at(1) + .simulate('click'); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + }); + + describe('load test', () => { + test('happy case with body set', async () => { + const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('text'); + }); + }); + const spyon2 = jest + .spyOn(S3Text.prototype, 'getText') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const s3Text = wrapper.instance(); + wrapper.setProps({ + textKey: 'textKey', + body: 'textBody', + }); + + await s3Text.load(); + + expect.assertions(2); + expect(spyon).toBeCalledWith('textKey', 'textBody', { + contentType: 'text/*', + level: 'public', + }); + expect(spyon2).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('nothing to do if no textKey and path set', async () => { + const wrapper = shallow(); + const s3Text = wrapper.instance(); + + await s3Text.load(); + }); + + test('only get text when body no specified', async () => { + const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('text'); + }); + }); + const spyon2 = jest + .spyOn(S3Text.prototype, 'getText') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const s3Text = wrapper.instance(); + wrapper.setProps({ + textKey: 'textKey', + }); + + await s3Text.load(); + + expect.assertions(2); + expect(spyon).not.toBeCalled(); + expect(spyon2).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + }); + + describe('handlePick test', () => { + test('happy case', async () => { + const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + const spyon2 = jest + .spyOn(S3Text.prototype, 'getText') + .mockImplementationOnce(() => { + return; + }); + + const wrapper = shallow(); + const s3Text = wrapper.instance(); + wrapper.setProps({ + text: 'text', + textKey: 'textKey', + level: 'level', + fileToKey: 'fileToKey', + }); + + const data = { + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }; + + await s3Text.handlePick(data); + + expect.assertions(2); + expect(spyon).toBeCalledWith('textKey', 'file', { + contentType: 'type', + level: 'level', + track: undefined, + }); + expect(spyon2).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + }); + + test('storage put error', async () => { + const spyon = jest.spyOn(Storage, 'put').mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + const wrapper = shallow(); + const s3Text = wrapper.instance(); + wrapper.setProps({ + text: 'text', + textKey: 'textKey', + level: 'level', + fileToKey: 'fileToKey', + }); + + const data = { + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }; + + await s3Text.handlePick(data); + + spyon.mockClear(); + }); + }); + + describe('handleClick test', () => { + test('happy case', () => { + const mockFn = jest.fn(); + const props = { + text: 'text', + textKey: 'textKey', + onClick: mockFn, + }; + + const wrapper = shallow(); + const s3Text = wrapper.instance(); + wrapper.setProps(props); + + s3Text.handleClick('evt'); + + expect(mockFn).toBeCalledWith('evt'); + }); + + test('if no onclick', () => { + const mockFn = jest.fn(); + const props = { + text: 'text', + textKey: 'textKey', + }; + const wrapper = shallow(); + const s3Text = wrapper.instance(); + wrapper.setProps(props); + + s3Text.handleClick('evt'); + }); + }); + + describe('handleOnLoad test', () => { + test('happy case', () => { + const mockFn = jest.fn(); + const props = { + text: 'text', + textKey: 'textKey', + onLoad: mockFn, + }; + const wrapper = shallow(); + const s3Text = wrapper.instance(); + wrapper.setProps(props); + + s3Text.handleOnLoad('text'); + + expect(mockFn).toBeCalledWith('text'); + }); + + test('if no onLoad', () => { + const mockFn = jest.fn(); + const props = { + text: 'text', + textKey: 'textKey', + }; + const wrapper = shallow(); + const s3Text = wrapper.instance(); + wrapper.setProps(props); + + s3Text.handleOnLoad('evt'); + }); + }); + + describe('handleOnError test', () => { + test('happy case', () => { + const mockFn = jest.fn(); + const props = { + text: 'text', + textKey: 'textKey', + onError: mockFn, + }; + const wrapper = shallow(); + const s3Text = wrapper.instance(); + wrapper.setProps(props); + + s3Text.handleOnError('err'); + + expect(mockFn).toBeCalledWith('err'); + }); + }); + + describe('textEl test', () => { + test('null text', () => { + const wrapper = shallow(); + const s3Text = wrapper.instance(); + + expect(s3Text.textEl(null, 'theme')).toBeNull(); + }); + }); + + describe('componentDidmount test', () => { + test('happy case', () => { + const spyon = jest.spyOn(S3Text.prototype, 'load'); + + const wrapper = mount(); + + expect(spyon).toBeCalled(); + spyon.mockClear(); + }); + }); + + describe('getText test', () => { + test('happy case', () => { + const wrapper = shallow(); + const s3Text = wrapper.instance(); + + const spyon = jest.spyOn(Storage, 'get').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('url'); + }); + }); + + s3Text.getText('key', 'level', false, 'identityId'); + expect(spyon).toBeCalledWith('key', { + download: true, + level: 'level', + track: false, + identityId: 'identityId', + }); + spyon.mockClear(); + }); + + test('error case', () => { + const wrapper = shallow(); + const s3Text = wrapper.instance(); + + const spyon = jest.spyOn(Storage, 'get').mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + try { + s3Text.getText('key', 'level', false); + } catch (e) { + expect(e).not.toBeNull(); + } + + spyon.mockClear(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Widget/PhotoPicker-test.js b/packages/aws-amplify-react/__tests__/Widget/PhotoPicker-test.js index c86c71502c8..38d5f4fc7fe 100644 --- a/packages/aws-amplify-react/__tests__/Widget/PhotoPicker-test.js +++ b/packages/aws-amplify-react/__tests__/Widget/PhotoPicker-test.js @@ -4,94 +4,100 @@ import PhotoPicker from '../../src/Widget/PhotoPicker'; import Picker from '../../src/Widget/Picker'; describe('PhotoPicker test', () => { - describe('render test', () => { - test('render with previewSrc', () => { - const wrapper = shallow(); - - wrapper.setState({previewSrc: true}); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render without previewSrc', () => { - const wrapper = shallow(); - - wrapper.setState({previewSrc: false}); - - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('interaction test', () => { - test('Picker pick test', () => { - const spyon = jest.spyOn(PhotoPicker.prototype, 'handlePick').mockImplementationOnce(() => { - return; - }); - const wrapper = shallow(); - - wrapper.find(Picker).simulate('pick'); - - expect(spyon).toBeCalled(); - }); - }); - - describe('hanldePick test', () => { - test('happy case', () => { - const spyon = jest.spyOn(FileReader.prototype, 'readAsDataURL').mockImplementationOnce(() => { - return; - }); - const onPickFn = jest.fn(); - const onLoadFn = jest.fn(); - - const data = { - file: 'file', - name: 'name', - size: 'size', - type: 'type' - }; - const props = { - preview: true, - onPick: onPickFn, - onLoad: onLoadFn - }; - const wrapper = shallow(); - const photoPicker = wrapper.instance(); - wrapper.setProps(props); - - photoPicker.handlePick(data); - - expect(onPickFn).toBeCalled(); - expect(spyon).toBeCalledWith('file'); - - spyon.mockClear(); - }); - - test('with no onPick and no preview', () => { - const spyon = jest.spyOn(FileReader.prototype, 'readAsDataURL').mockImplementationOnce(() => { - return; - }); - - const onLoadFn = jest.fn(); - - const data = { - file: 'file', - name: 'name', - size: 'size', - type: 'type' - }; - const props = { - preview: false, - onLoad: onLoadFn - }; - const wrapper = shallow(); - const photoPicker = wrapper.instance(); - wrapper.setProps(props); - - photoPicker.handlePick(data); - - expect(spyon).not.toBeCalledWith('file'); - - spyon.mockClear(); - }); - }); + describe('render test', () => { + test('render with previewSrc', () => { + const wrapper = shallow(); + + wrapper.setState({ previewSrc: true }); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render without previewSrc', () => { + const wrapper = shallow(); + + wrapper.setState({ previewSrc: false }); + + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('interaction test', () => { + test('Picker pick test', () => { + const spyon = jest + .spyOn(PhotoPicker.prototype, 'handlePick') + .mockImplementationOnce(() => { + return; + }); + const wrapper = shallow(); + + wrapper.find(Picker).simulate('pick'); + + expect(spyon).toBeCalled(); + }); + }); + + describe('hanldePick test', () => { + test('happy case', () => { + const spyon = jest + .spyOn(FileReader.prototype, 'readAsDataURL') + .mockImplementationOnce(() => { + return; + }); + const onPickFn = jest.fn(); + const onLoadFn = jest.fn(); + + const data = { + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }; + const props = { + preview: true, + onPick: onPickFn, + onLoad: onLoadFn, + }; + const wrapper = shallow(); + const photoPicker = wrapper.instance(); + wrapper.setProps(props); + + photoPicker.handlePick(data); + + expect(onPickFn).toBeCalled(); + expect(spyon).toBeCalledWith('file'); + + spyon.mockClear(); + }); + + test('with no onPick and no preview', () => { + const spyon = jest + .spyOn(FileReader.prototype, 'readAsDataURL') + .mockImplementationOnce(() => { + return; + }); + + const onLoadFn = jest.fn(); + + const data = { + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }; + const props = { + preview: false, + onLoad: onLoadFn, + }; + const wrapper = shallow(); + const photoPicker = wrapper.instance(); + wrapper.setProps(props); + + photoPicker.handlePick(data); + + expect(spyon).not.toBeCalledWith('file'); + + spyon.mockClear(); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Widget/Picker-test.js b/packages/aws-amplify-react/__tests__/Widget/Picker-test.js index 9ba426ce543..bfa674300bb 100644 --- a/packages/aws-amplify-react/__tests__/Widget/Picker-test.js +++ b/packages/aws-amplify-react/__tests__/Widget/Picker-test.js @@ -2,73 +2,82 @@ import * as React from 'react'; import Picker from '../../src/Widget/Picker'; describe('Picker test', () => { - describe('render test', () => { - test('render correcly', () => { - const wrapper = shallow(); + describe('render test', () => { + test('render correcly', () => { + const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - }); + expect(wrapper).toMatchSnapshot(); + }); + }); - describe('interaction test', () => { - test('chnage on input', () => { - const spyon = jest.spyOn(Picker.prototype, 'handleInput').mockImplementationOnce(() => { - return; - }); + describe('interaction test', () => { + test('chnage on input', () => { + const spyon = jest + .spyOn(Picker.prototype, 'handleInput') + .mockImplementationOnce(() => { + return; + }); - const wrapper = shallow(); + const wrapper = shallow(); - wrapper.find('input').at(0).simulate('change', 'event'); + wrapper + .find('input') + .at(0) + .simulate('change', 'event'); - expect(spyon).toBeCalledWith('event'); + expect(spyon).toBeCalledWith('event'); - spyon.mockClear(); - }); - }); + spyon.mockClear(); + }); + }); - describe('handleInput test', () => { - test('happy case', () => { - const onPickFn = jest.fn(); + describe('handleInput test', () => { + test('happy case', () => { + const onPickFn = jest.fn(); - const wrapper = shallow(); - const picker = wrapper.instance(); - wrapper.setProps({ - onPick: onPickFn - }); + const wrapper = shallow(); + const picker = wrapper.instance(); + wrapper.setProps({ + onPick: onPickFn, + }); - const event = { - target: { - files:[{ - name: 'name', - size: 'size', - type: 'type' - }] - } - }; - picker.handleInput(event); - - expect(onPickFn).toBeCalledWith({"file": {"name": "name", "size": "size", "type": "type"}, - "name": "name", - "size": "size", - "type": "type"}); - }); + const event = { + target: { + files: [ + { + name: 'name', + size: 'size', + type: 'type', + }, + ], + }, + }; + picker.handleInput(event); - test('no onPick', () => { - const wrapper = shallow(); - const picker = wrapper.instance(); - - const event = { - target: { - files:[{ - name: 'name', - size: 'size', - type: 'type' - }] - } - }; - picker.handleInput(event); - }); - }); + expect(onPickFn).toBeCalledWith({ + file: { name: 'name', size: 'size', type: 'type' }, + name: 'name', + size: 'size', + type: 'type', + }); + }); + test('no onPick', () => { + const wrapper = shallow(); + const picker = wrapper.instance(); + const event = { + target: { + files: [ + { + name: 'name', + size: 'size', + type: 'type', + }, + ], + }, + }; + picker.handleInput(event); + }); + }); }); diff --git a/packages/aws-amplify-react/__tests__/Widget/SelectMFAType-test.js b/packages/aws-amplify-react/__tests__/Widget/SelectMFAType-test.js index 7f9a4ab8b15..bc24588c49e 100644 --- a/packages/aws-amplify-react/__tests__/Widget/SelectMFAType-test.js +++ b/packages/aws-amplify-react/__tests__/Widget/SelectMFAType-test.js @@ -1,222 +1,237 @@ import Auth from '@aws-amplify/auth'; import * as React from 'react'; import SelectMFAType from '../../src/Widget/SelectMFAType'; -import { Header, Footer, Input, Button, Link } from '../../src/Amplify-UI/Amplify-UI-Components-React'; +import { + Header, + Footer, + Input, + Button, + Link, +} from '../../src/Amplify-UI/Amplify-UI-Components-React'; import AmplifyTheme from '../../src/AmplifyTheme'; - describe('SelectMFAType test', () => { - describe('render test', () => { - test('render without totpsetup and with all mfa types and select message', () => { - const MFATypes = { - SMS: true, - TOTP: true, - Optional: true - }; - const wrapper = shallow(); - - wrapper.setState({TOTPSetup: false}); - wrapper.setState({selectMessage: 'message'}); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render without totpsetup and with less than 2 mfa types', () => { - const MFATypes = { - SMS: true - }; - const wrapper = shallow(); - - wrapper.setState({TOTPSetup: false}); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render without totpsetup and with 2 mfa types', () => { - const MFATypes = { - SMS: true, - TOTP: true - }; - const wrapper = shallow(); - - wrapper.setState({TOTPSetup: false}); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render with totpsetup and with all mfa types and select message', () => { - const MFATypes = { - SMS: true, - TOTP: true, - Optional: true - }; - const wrapper = shallow(); - - wrapper.setState({TOTPSetup: true}); - wrapper.setState({selectMessage: 'message'}); - - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('interaction test', () => { - test('verify button click test', () => { - const spyon = jest.spyOn(SelectMFAType.prototype, 'verify').mockImplementationOnce(() => { - return; - }); - const MFATypes = { - SMS: true, - TOTP: true, - Optional: true - }; - const wrapper = shallow(); - - wrapper.find(Button).simulate('click'); - - expect(spyon).toBeCalled(); - }); - }); - - describe('hanldeInputChange test', () => { - test('happy case', () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const evt = { - target: { - name: 'name', - value: 'value', - type: 'radio', - checked: true - } - }; - instance.handleInputChange(evt); - }); - }); - - describe('verify test', () => { - test('happy case with SMS', async () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const evt = { - target: { - name: 'MFAType', - value: 'SMS', - type: 'radio', - checked: true - } - }; - instance.handleInputChange(evt); - - const spyon = jest.spyOn(Auth, 'setPreferredMFA').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - await instance.verify(); - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - - test('happy case with SMS', async () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const evt = { - target: { - name: 'MFAType', - value: 'NOMFA', - type: 'radio', - checked: true - } - }; - instance.handleInputChange(evt); - - const spyon = jest.spyOn(Auth, 'setPreferredMFA').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - await instance.verify(); - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - - test('happy case without inputs', async () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'setPreferredMFA').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res('data'); - }); - }); - - await instance.verify(); - expect(spyon).not.toBeCalled(); - - spyon.mockClear(); - }); - - test('happy case with TOTP not setup yet', async () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const evt = { - target: { - name: 'MFAType', - value: 'TOTP', - type: 'radio', - checked: true - } - }; - instance.handleInputChange(evt); - - const spyon = jest.spyOn(Auth, 'setPreferredMFA').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej({ - message: 'User has not set up software token mfa' - }); - }); - }); - - await instance.verify(); - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - - test('error case', async () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const evt = { - target: { - name: 'MFAType', - value: 'SMS', - type: 'radio', - checked: true - } - }; - instance.handleInputChange(evt); - - const spyon = jest.spyOn(Auth, 'setPreferredMFA').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej('err'); - }); - }); - - await instance.verify(); - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - }); + describe('render test', () => { + test('render without totpsetup and with all mfa types and select message', () => { + const MFATypes = { + SMS: true, + TOTP: true, + Optional: true, + }; + const wrapper = shallow(); + + wrapper.setState({ TOTPSetup: false }); + wrapper.setState({ selectMessage: 'message' }); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render without totpsetup and with less than 2 mfa types', () => { + const MFATypes = { + SMS: true, + }; + const wrapper = shallow(); + + wrapper.setState({ TOTPSetup: false }); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render without totpsetup and with 2 mfa types', () => { + const MFATypes = { + SMS: true, + TOTP: true, + }; + const wrapper = shallow(); + + wrapper.setState({ TOTPSetup: false }); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render with totpsetup and with all mfa types and select message', () => { + const MFATypes = { + SMS: true, + TOTP: true, + Optional: true, + }; + const wrapper = shallow(); + + wrapper.setState({ TOTPSetup: true }); + wrapper.setState({ selectMessage: 'message' }); + + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('interaction test', () => { + test('verify button click test', () => { + const spyon = jest + .spyOn(SelectMFAType.prototype, 'verify') + .mockImplementationOnce(() => { + return; + }); + const MFATypes = { + SMS: true, + TOTP: true, + Optional: true, + }; + const wrapper = shallow(); + + wrapper.find(Button).simulate('click'); + + expect(spyon).toBeCalled(); + }); + }); + + describe('hanldeInputChange test', () => { + test('happy case', () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const evt = { + target: { + name: 'name', + value: 'value', + type: 'radio', + checked: true, + }, + }; + instance.handleInputChange(evt); + }); + }); + + describe('verify test', () => { + test('happy case with SMS', async () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const evt = { + target: { + name: 'MFAType', + value: 'SMS', + type: 'radio', + checked: true, + }, + }; + instance.handleInputChange(evt); + + const spyon = jest + .spyOn(Auth, 'setPreferredMFA') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + await instance.verify(); + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + + test('happy case with SMS', async () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const evt = { + target: { + name: 'MFAType', + value: 'NOMFA', + type: 'radio', + checked: true, + }, + }; + instance.handleInputChange(evt); + + const spyon = jest + .spyOn(Auth, 'setPreferredMFA') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + await instance.verify(); + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + + test('happy case without inputs', async () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'setPreferredMFA') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res('data'); + }); + }); + + await instance.verify(); + expect(spyon).not.toBeCalled(); + + spyon.mockClear(); + }); + + test('happy case with TOTP not setup yet', async () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const evt = { + target: { + name: 'MFAType', + value: 'TOTP', + type: 'radio', + checked: true, + }, + }; + instance.handleInputChange(evt); + + const spyon = jest + .spyOn(Auth, 'setPreferredMFA') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej({ + message: 'User has not set up software token mfa', + }); + }); + }); + + await instance.verify(); + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + + test('error case', async () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const evt = { + target: { + name: 'MFAType', + value: 'SMS', + type: 'radio', + checked: true, + }, + }; + instance.handleInputChange(evt); + + const spyon = jest + .spyOn(Auth, 'setPreferredMFA') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej('err'); + }); + }); + + await instance.verify(); + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + }); }); - - diff --git a/packages/aws-amplify-react/__tests__/Widget/TOTPSetupComp-test.js b/packages/aws-amplify-react/__tests__/Widget/TOTPSetupComp-test.js index 85fee64da66..eaf9b3a8cb3 100644 --- a/packages/aws-amplify-react/__tests__/Widget/TOTPSetupComp-test.js +++ b/packages/aws-amplify-react/__tests__/Widget/TOTPSetupComp-test.js @@ -2,195 +2,212 @@ import Auth from '@aws-amplify/auth'; import * as React from 'react'; import { Component } from 'react'; import TOTPSetupComp from '../../src/Widget/TOTPSetupComp'; -import { Header, Footer, InputRow, Button, Link } from '../../src/Amplify-UI/Amplify-UI-Components-React'; +import { + Header, + Footer, + InputRow, + Button, + Link, +} from '../../src/Amplify-UI/Amplify-UI-Components-React'; import AmplifyTheme from '../../src/AmplifyTheme'; - describe('TOTPSetupComp test', () => { - describe('render test', () => { - test('render without code or setupMessage', () => { - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render with code and setupMessage', () => { - const wrapper = shallow(); - wrapper.setState({code: 'code'}); - wrapper.setState({setupMessage: 'message'}); - - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('interaction test', () => { - test('verify button test', () => { - const spyon = jest.spyOn(TOTPSetupComp.prototype, 'verifyTotpToken').mockImplementationOnce(() => { - return; - }); - const wrapper = shallow(); - wrapper.setState({code: 'code'}); - - wrapper.find(Button).simulate('click'); - - expect(spyon).toBeCalled(); - }); - - test('get secret key button test', () => { - const spyon = jest.spyOn(TOTPSetupComp.prototype, 'setup').mockImplementationOnce(() => { - return; - }); - const wrapper = shallow(); - - wrapper.find(Button).simulate('click'); - - expect(spyon).toBeCalled(); - }); - }); - - describe('hanldeInputChange test', () => { - test('happy case', () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const evt = { - target: { - name: 'name', - value: 'value' - } - }; - instance.handleInputChange(evt); - }); - }); - - describe('setup test', () => { - test('happy case', async () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'setupTOTP').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(); - }); - }); - - await instance.setup(); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - - test('error case', async () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'setupTOTP').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej(); - }); - }); - - await instance.setup(); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - }); - - describe('triggerTOTPEvent test', () => { - test('happy case', () => { - const mockFn = jest.fn(); - const wrapper = shallow(); - const instance = wrapper.instance(); - - instance.triggerTOTPEvent('event', 'data', 'user'); - - expect(mockFn).toBeCalledWith('event', 'data', 'user'); - }); - }); - - describe('verifyTotpToken test', () => { - test('happy case', async () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const evt = { - target: { - name: 'name', - value: 'value' - } - }; - instance.handleInputChange(evt); - - const spyon = jest.spyOn(Auth, 'verifyTotpToken').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(); - }); - }); - const spyon2 = jest.spyOn(Auth, 'setPreferredMFA').mockImplementationOnce(() => { - return; - }); - const spyon3 = jest.spyOn(instance, 'triggerTOTPEvent'); - - await instance.verifyTotpToken(); - - expect(spyon).toBeCalled(); - expect(spyon2).toBeCalled(); - expect(spyon3).toBeCalled(); - - spyon.mockClear(); - spyon2.mockClear(); - spyon3.mockClear(); - }); - - test('no input', async () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const spyon = jest.spyOn(Auth, 'verifyTotpToken').mockImplementationOnce(() => { - return new Promise((res, rej) => { - res(); - }); - }); - - await instance.verifyTotpToken(); - - expect(spyon).not.toBeCalled(); - - spyon.mockClear(); - }); - - test('error case', async () => { - const wrapper = shallow(); - const instance = wrapper.instance(); - - const evt = { - target: { - name: 'name', - value: 'value' - } - }; - instance.handleInputChange(evt); - - const spyon = jest.spyOn(Auth, 'verifyTotpToken').mockImplementationOnce(() => { - return new Promise((res, rej) => { - rej(); - }); - }); - const spyon2 = jest.spyOn(Auth, 'setPreferredMFA').mockImplementationOnce(() => { - return; - }); - const spyon3 = jest.spyOn(instance, 'triggerTOTPEvent'); - - await instance.verifyTotpToken(); - - expect(spyon).toBeCalled(); - - spyon.mockClear(); - }); - }); + describe('render test', () => { + test('render without code or setupMessage', () => { + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render with code and setupMessage', () => { + const wrapper = shallow(); + wrapper.setState({ code: 'code' }); + wrapper.setState({ setupMessage: 'message' }); + + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('interaction test', () => { + test('verify button test', () => { + const spyon = jest + .spyOn(TOTPSetupComp.prototype, 'verifyTotpToken') + .mockImplementationOnce(() => { + return; + }); + const wrapper = shallow(); + wrapper.setState({ code: 'code' }); + + wrapper.find(Button).simulate('click'); + + expect(spyon).toBeCalled(); + }); + + test('get secret key button test', () => { + const spyon = jest + .spyOn(TOTPSetupComp.prototype, 'setup') + .mockImplementationOnce(() => { + return; + }); + const wrapper = shallow(); + + wrapper.find(Button).simulate('click'); + + expect(spyon).toBeCalled(); + }); + }); + + describe('hanldeInputChange test', () => { + test('happy case', () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const evt = { + target: { + name: 'name', + value: 'value', + }, + }; + instance.handleInputChange(evt); + }); + }); + + describe('setup test', () => { + test('happy case', async () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const spyon = jest.spyOn(Auth, 'setupTOTP').mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(); + }); + }); + + await instance.setup(); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + + test('error case', async () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const spyon = jest.spyOn(Auth, 'setupTOTP').mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej(); + }); + }); + + await instance.setup(); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + }); + + describe('triggerTOTPEvent test', () => { + test('happy case', () => { + const mockFn = jest.fn(); + const wrapper = shallow(); + const instance = wrapper.instance(); + + instance.triggerTOTPEvent('event', 'data', 'user'); + + expect(mockFn).toBeCalledWith('event', 'data', 'user'); + }); + }); + + describe('verifyTotpToken test', () => { + test('happy case', async () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const evt = { + target: { + name: 'name', + value: 'value', + }, + }; + instance.handleInputChange(evt); + + const spyon = jest + .spyOn(Auth, 'verifyTotpToken') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(); + }); + }); + const spyon2 = jest + .spyOn(Auth, 'setPreferredMFA') + .mockImplementationOnce(() => { + return; + }); + const spyon3 = jest.spyOn(instance, 'triggerTOTPEvent'); + + await instance.verifyTotpToken(); + + expect(spyon).toBeCalled(); + expect(spyon2).toBeCalled(); + expect(spyon3).toBeCalled(); + + spyon.mockClear(); + spyon2.mockClear(); + spyon3.mockClear(); + }); + + test('no input', async () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const spyon = jest + .spyOn(Auth, 'verifyTotpToken') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + res(); + }); + }); + + await instance.verifyTotpToken(); + + expect(spyon).not.toBeCalled(); + + spyon.mockClear(); + }); + + test('error case', async () => { + const wrapper = shallow(); + const instance = wrapper.instance(); + + const evt = { + target: { + name: 'name', + value: 'value', + }, + }; + instance.handleInputChange(evt); + + const spyon = jest + .spyOn(Auth, 'verifyTotpToken') + .mockImplementationOnce(() => { + return new Promise((res, rej) => { + rej(); + }); + }); + const spyon2 = jest + .spyOn(Auth, 'setPreferredMFA') + .mockImplementationOnce(() => { + return; + }); + const spyon3 = jest.spyOn(instance, 'triggerTOTPEvent'); + + await instance.verifyTotpToken(); + + expect(spyon).toBeCalled(); + + spyon.mockClear(); + }); + }); }); - - diff --git a/packages/aws-amplify-react/__tests__/Widget/TextPicker-test.js b/packages/aws-amplify-react/__tests__/Widget/TextPicker-test.js index cb283911db9..652c80a154e 100644 --- a/packages/aws-amplify-react/__tests__/Widget/TextPicker-test.js +++ b/packages/aws-amplify-react/__tests__/Widget/TextPicker-test.js @@ -3,96 +3,100 @@ import TextPicker from '../../src/Widget/TextPicker'; import Picker from '../../src/Widget/Picker'; describe('TextPicker test', () => { - describe('render test', () => { - test('render with previewSrc', () => { - const wrapper = shallow(); - - wrapper.setState({previewText: true}); - - expect(wrapper).toMatchSnapshot(); - }); - - test('render without previewText', () => { - const wrapper = shallow(); - - wrapper.setState({previewText: false}); - - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('interaction test', () => { - test('Picker pick test', () => { - const spyon = jest.spyOn(TextPicker.prototype, 'handlePick').mockImplementationOnce(() => { - return; - }); - const wrapper = shallow(); - - wrapper.find(Picker).simulate('pick'); - - expect(spyon).toBeCalled(); - }); - }); - - describe('hanldePick test', () => { - test('happy case', () => { - const spyon = jest.spyOn(FileReader.prototype, 'readAsText').mockImplementationOnce(() => { - return; - }); - const onPickFn = jest.fn(); - const onLoadFn = jest.fn(); - - const data = { - file: 'file', - name: 'name', - size: 'size', - type: 'type' - }; - const props = { - preview: true, - onPick: onPickFn, - onLoad: onLoadFn - }; - const wrapper = shallow(); - const textPicker = wrapper.instance(); - wrapper.setProps(props); - - textPicker.handlePick(data); - - expect(onPickFn).toBeCalled(); - expect(spyon).toBeCalledWith('file'); - - spyon.mockClear(); - }); - - test('with no onPick and no preview', () => { - const spyon = jest.spyOn(FileReader.prototype, 'readAsText').mockImplementationOnce(() => { - return; - }); - - const onLoadFn = jest.fn(); - - const data = { - file: 'file', - name: 'name', - size: 'size', - type: 'type' - }; - const props = { - preview: false, - onLoad: onLoadFn - }; - const wrapper = shallow(); - const textPicker = wrapper.instance(); - wrapper.setProps(props); - - textPicker.handlePick(data); - - expect(spyon).not.toBeCalledWith('file'); - - spyon.mockClear(); - }); - }); + describe('render test', () => { + test('render with previewSrc', () => { + const wrapper = shallow(); + + wrapper.setState({ previewText: true }); + + expect(wrapper).toMatchSnapshot(); + }); + + test('render without previewText', () => { + const wrapper = shallow(); + + wrapper.setState({ previewText: false }); + + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('interaction test', () => { + test('Picker pick test', () => { + const spyon = jest + .spyOn(TextPicker.prototype, 'handlePick') + .mockImplementationOnce(() => { + return; + }); + const wrapper = shallow(); + + wrapper.find(Picker).simulate('pick'); + + expect(spyon).toBeCalled(); + }); + }); + + describe('hanldePick test', () => { + test('happy case', () => { + const spyon = jest + .spyOn(FileReader.prototype, 'readAsText') + .mockImplementationOnce(() => { + return; + }); + const onPickFn = jest.fn(); + const onLoadFn = jest.fn(); + + const data = { + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }; + const props = { + preview: true, + onPick: onPickFn, + onLoad: onLoadFn, + }; + const wrapper = shallow(); + const textPicker = wrapper.instance(); + wrapper.setProps(props); + + textPicker.handlePick(data); + + expect(onPickFn).toBeCalled(); + expect(spyon).toBeCalledWith('file'); + + spyon.mockClear(); + }); + + test('with no onPick and no preview', () => { + const spyon = jest + .spyOn(FileReader.prototype, 'readAsText') + .mockImplementationOnce(() => { + return; + }); + + const onLoadFn = jest.fn(); + + const data = { + file: 'file', + name: 'name', + size: 'size', + type: 'type', + }; + const props = { + preview: false, + onLoad: onLoadFn, + }; + const wrapper = shallow(); + const textPicker = wrapper.instance(); + wrapper.setProps(props); + + textPicker.handlePick(data); + + expect(spyon).not.toBeCalledWith('file'); + + spyon.mockClear(); + }); + }); }); - - diff --git a/packages/aws-amplify-react/__tests__/XR/IconButton-test.js b/packages/aws-amplify-react/__tests__/XR/IconButton-test.js index 28e9ef8e2ad..3726da60a08 100644 --- a/packages/aws-amplify-react/__tests__/XR/IconButton-test.js +++ b/packages/aws-amplify-react/__tests__/XR/IconButton-test.js @@ -2,13 +2,13 @@ import * as React from 'react'; import IconButton from '../../src/XR/IconButton'; describe('IconButton', () => { - test('renders successfully with no variant', () => { - const wrapper = mount(); - expect(wrapper).toMatchSnapshot(); - }); + test('renders successfully with no variant', () => { + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + }); - test('renders successfully with variant', () => { - const wrapper = mount(); - expect(wrapper).toMatchSnapshot(); - }); -}); \ No newline at end of file + test('renders successfully with variant', () => { + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/packages/aws-amplify-react/__tests__/XR/Loading-test.js b/packages/aws-amplify-react/__tests__/XR/Loading-test.js index 603ccee2371..a271c10187e 100644 --- a/packages/aws-amplify-react/__tests__/XR/Loading-test.js +++ b/packages/aws-amplify-react/__tests__/XR/Loading-test.js @@ -2,13 +2,13 @@ import * as React from 'react'; import Loading from '../../src/XR/Loading'; describe('Loading', () => { - test('renders successfully with no props', () => { - const wrapper = mount(); - expect(wrapper).toMatchSnapshot(); - }); + test('renders successfully with no props', () => { + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + }); - test('renders successfully with percentage', () => { - const wrapper = mount(); - expect(wrapper).toMatchSnapshot(); - }); -}); \ No newline at end of file + test('renders successfully with percentage', () => { + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/packages/aws-amplify-react/__tests__/XR/SumerianScene-test.js b/packages/aws-amplify-react/__tests__/XR/SumerianScene-test.js index a7ba78aee89..97783e394d6 100644 --- a/packages/aws-amplify-react/__tests__/XR/SumerianScene-test.js +++ b/packages/aws-amplify-react/__tests__/XR/SumerianScene-test.js @@ -4,30 +4,30 @@ import XR from '@aws-amplify/xr'; const sceneConfig = {}; XR.configure({ - region: 'us-east-1', - scenes: { - "TestSceneName": { // Friendly scene name - sceneConfig: sceneConfig // Scene configuration from Sumerian publish - } - } + region: 'us-east-1', + scenes: { + TestSceneName: { + // Friendly scene name + sceneConfig: sceneConfig, // Scene configuration from Sumerian publish + }, + }, }); describe('SumerianScene', () => { - test('renders successfully', () => { - const wrapper = mount(); - expect(wrapper).toMatchSnapshot(); - }); + test('renders successfully', () => { + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + }); + test('loadAndSetupScene is called when component is mounted', () => { + const spy = jest.spyOn(SumerianScene.prototype, 'loadAndSetupScene'); + mount(); + expect(spy).toHaveBeenCalled(); + }); - test('loadAndSetupScene is called when component is mounted', () => { - const spy = jest.spyOn(SumerianScene.prototype, 'loadAndSetupScene'); - mount(); - expect(spy).toHaveBeenCalled(); - }); - - test('loadScene from XR module is called when component is mounted', () => { - const spy = jest.spyOn(XR, 'loadScene'); - shallow(); - expect(spy).toHaveBeenCalled(); - }); -}); \ No newline at end of file + test('loadScene from XR module is called when component is mounted', () => { + const spy = jest.spyOn(XR, 'loadScene'); + shallow(); + expect(spy).toHaveBeenCalled(); + }); +}); diff --git a/packages/aws-amplify-react/__tests__/XR/Tooltip-test.js b/packages/aws-amplify-react/__tests__/XR/Tooltip-test.js index ff4783e6553..051710299b2 100644 --- a/packages/aws-amplify-react/__tests__/XR/Tooltip-test.js +++ b/packages/aws-amplify-react/__tests__/XR/Tooltip-test.js @@ -2,13 +2,13 @@ import * as React from 'react'; import Tooltip from '../../src/XR/Tooltip'; describe('Tooltip', () => { - test('renders successfully with no props', () => { - const wrapper = mount(); - expect(wrapper).toMatchSnapshot(); - }); + test('renders successfully with no props', () => { + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + }); - test('renders successfully with text', () => { - const wrapper = mount(); - expect(wrapper).toMatchSnapshot(); - }); -}); \ No newline at end of file + test('renders successfully with text', () => { + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/packages/aws-amplify-react/src/API/GraphQL/Connect.js b/packages/aws-amplify-react/src/API/GraphQL/Connect.js index 1a176fdcc81..343b8a64d28 100644 --- a/packages/aws-amplify-react/src/API/GraphQL/Connect.js +++ b/packages/aws-amplify-react/src/API/GraphQL/Connect.js @@ -2,149 +2,164 @@ import regeneratorRuntime from 'regenerator-runtime/runtime'; import { Component } from 'react'; import API from '@aws-amplify/api'; - - export default class Connect extends Component { - - constructor(props) { - super(props); - - this.state = this.getInitialState(); - this.subSubscription = null; - } - - getInitialState() { - const { query } = this.props; - return { - loading: query && !!query.query, - data: {}, - errors: [], - mutation: () => console.warn('Not implemented'), - }; - } - - getDefaultState() { - return { - loading: false, - data: {}, - errors: [], - mutation: () => console.warn('Not implemented'), - }; - } - - async _fetchData() { - this._unsubscribe(); - this.setState({ loading: true }); - - const { - query: { query, variables = {} } = {}, - mutation: { query: mutation, mutationVariables = {} } = {}, - subscription, - onSubscriptionMsg = (prevData) => prevData, - } = this.props; - - let { data, mutation: mutationProp, errors } = this.getDefaultState(); - - if (!API || typeof API.graphql !== 'function' || typeof API.getGraphqlOperationType !== 'function') { - throw new Error('No API module found, please ensure @aws-amplify/api is imported'); - } - - const hasValidQuery = query && API.getGraphqlOperationType(query) === 'query'; - const hasValidMutation = mutation && API.getGraphqlOperationType(mutation) === 'mutation'; - const hasValidSubscription = subscription && API.getGraphqlOperationType(subscription.query) === 'subscription'; - - if (!hasValidQuery && !hasValidMutation && !hasValidSubscription) { - console.warn('No query, mutation or subscription was specified'); - } - - if (hasValidQuery) { - try { - data = null; - - const response = await API.graphql({ query, variables }); - - data = response.data; - } catch (err) { - data = err.data; - errors = err.errors; - } - } - - if (hasValidMutation) { - mutationProp = async (variables) => { - const result = await API.graphql({ query: mutation, variables }); - - this.forceUpdate(); - return result; - }; - } - - if (hasValidSubscription) { - const { query: subsQuery, variables: subsVars } = subscription; - - try { - const observable = API.graphql({ query: subsQuery, variables: subsVars }); - - this.subSubscription = observable.subscribe({ - next: ({ value: { data } }) => { - const { data: prevData } = this.state; - const newData = onSubscriptionMsg(prevData, data); - if (this.mounted) { - this.setState({ data: newData }); - } - }, - error: err => console.error(err), - }); - } catch (err) { - errors = err.errors; - } - } - - this.setState({ data, errors, mutation: mutationProp, loading: false }); - } - - _unsubscribe() { - if (this.subSubscription) { - this.subSubscription.unsubscribe(); - } - } - - async componentDidMount() { - this._fetchData(); - this.mounted = true; - } - - componentWillUnmount() { - this._unsubscribe(); - this.mounted = false; - } - - componentDidUpdate(prevProps) { - const { loading } = this.state; - - const { query: newQueryObj, mutation: newMutationObj } = this.props; - const { query: prevQueryObj, mutation: prevMutationObj } = prevProps; - - // query - const { query: newQuery, variables: newQueryVariables } = newQueryObj || {}; - const { query: prevQuery, variables: prevQueryVariables } = prevQueryObj || {}; - const queryChanged = - prevQuery !== newQuery || JSON.stringify(prevQueryVariables) !== JSON.stringify(newQueryVariables); - - // mutation - const { query: newMutation, variables: newMutationVariables } = newMutationObj || {}; - const { query: prevMutation, variables: prevMutationVariables } = prevMutationObj || {}; - const mutationChanged = - prevMutation !== newMutation - || JSON.stringify(prevMutationVariables) !== JSON.stringify(newMutationVariables); - - if (!loading && (queryChanged || mutationChanged)) { - this._fetchData(); - } - } - - render() { - const { data, loading, mutation, errors } = this.state; - return this.props.children({ data, errors, loading, mutation }) || null; - } + constructor(props) { + super(props); + + this.state = this.getInitialState(); + this.subSubscription = null; + } + + getInitialState() { + const { query } = this.props; + return { + loading: query && !!query.query, + data: {}, + errors: [], + mutation: () => console.warn('Not implemented'), + }; + } + + getDefaultState() { + return { + loading: false, + data: {}, + errors: [], + mutation: () => console.warn('Not implemented'), + }; + } + + async _fetchData() { + this._unsubscribe(); + this.setState({ loading: true }); + + const { + query: { query, variables = {} } = {}, + mutation: { query: mutation, mutationVariables = {} } = {}, + subscription, + onSubscriptionMsg = prevData => prevData, + } = this.props; + + let { data, mutation: mutationProp, errors } = this.getDefaultState(); + + if ( + !API || + typeof API.graphql !== 'function' || + typeof API.getGraphqlOperationType !== 'function' + ) { + throw new Error( + 'No API module found, please ensure @aws-amplify/api is imported' + ); + } + + const hasValidQuery = + query && API.getGraphqlOperationType(query) === 'query'; + const hasValidMutation = + mutation && API.getGraphqlOperationType(mutation) === 'mutation'; + const hasValidSubscription = + subscription && + API.getGraphqlOperationType(subscription.query) === 'subscription'; + + if (!hasValidQuery && !hasValidMutation && !hasValidSubscription) { + console.warn('No query, mutation or subscription was specified'); + } + + if (hasValidQuery) { + try { + data = null; + + const response = await API.graphql({ query, variables }); + + data = response.data; + } catch (err) { + data = err.data; + errors = err.errors; + } + } + + if (hasValidMutation) { + mutationProp = async variables => { + const result = await API.graphql({ query: mutation, variables }); + + this.forceUpdate(); + return result; + }; + } + + if (hasValidSubscription) { + const { query: subsQuery, variables: subsVars } = subscription; + + try { + const observable = API.graphql({ + query: subsQuery, + variables: subsVars, + }); + + this.subSubscription = observable.subscribe({ + next: ({ value: { data } }) => { + const { data: prevData } = this.state; + const newData = onSubscriptionMsg(prevData, data); + if (this.mounted) { + this.setState({ data: newData }); + } + }, + error: err => console.error(err), + }); + } catch (err) { + errors = err.errors; + } + } + + this.setState({ data, errors, mutation: mutationProp, loading: false }); + } + + _unsubscribe() { + if (this.subSubscription) { + this.subSubscription.unsubscribe(); + } + } + + async componentDidMount() { + this._fetchData(); + this.mounted = true; + } + + componentWillUnmount() { + this._unsubscribe(); + this.mounted = false; + } + + componentDidUpdate(prevProps) { + const { loading } = this.state; + + const { query: newQueryObj, mutation: newMutationObj } = this.props; + const { query: prevQueryObj, mutation: prevMutationObj } = prevProps; + + // query + const { query: newQuery, variables: newQueryVariables } = newQueryObj || {}; + const { query: prevQuery, variables: prevQueryVariables } = + prevQueryObj || {}; + const queryChanged = + prevQuery !== newQuery || + JSON.stringify(prevQueryVariables) !== JSON.stringify(newQueryVariables); + + // mutation + const { query: newMutation, variables: newMutationVariables } = + newMutationObj || {}; + const { query: prevMutation, variables: prevMutationVariables } = + prevMutationObj || {}; + const mutationChanged = + prevMutation !== newMutation || + JSON.stringify(prevMutationVariables) !== + JSON.stringify(newMutationVariables); + + if (!loading && (queryChanged || mutationChanged)) { + this._fetchData(); + } + } + + render() { + const { data, loading, mutation, errors } = this.state; + return this.props.children({ data, errors, loading, mutation }) || null; + } } diff --git a/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Components-React.jsx b/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Components-React.jsx index e6b4cb8d819..2699adf90f0 100644 --- a/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Components-React.jsx +++ b/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Components-React.jsx @@ -2,435 +2,444 @@ import * as React from 'react'; import { JS } from '@aws-amplify/core'; -import "@aws-amplify/ui/dist/style.css"; +import '@aws-amplify/ui/dist/style.css'; import * as AmplifyUI from '@aws-amplify/ui'; import AmplifyTheme from './Amplify-UI-Theme'; -export const Container = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.container); - const p = JS.objectLessAttributes(props, 'theme'); - - return beforeAfter( -
- {props.children} -
- ); -}; - -export const FormContainer = (props) => { - const theme = props.theme || AmplifyTheme; - return beforeAfter( -
- {props.children} -
- ); -}; - -export const FormSection = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.formSection); - return ( - - {beforeAfter( -
- {props.children} -
- )} -
- ); -}; - -export const SectionHeader = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.sectionHeader); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- - {props.children} - {props.hint && -
- {props.hint} -
- } -
-
- ); -}; - -export const SectionHeaderContent = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.sectionHeaderContent); - return beforeAfter( - - {props.children} - - ); -}; - -export const SectionFooter = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.sectionFooter); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const SectionFooterPrimaryContent = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.sectionFooterPrimaryContent); - return beforeAfter( - - {props.children} - - ); -}; - -export const SectionFooterSecondaryContent = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.sectionFooterSecondaryContent); - return beforeAfter( - - {props.children} - - ); -}; - -export const SectionBody = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.sectionBody); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const ActionRow = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.actionRow); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const Strike = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.strike); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const StrikeContent = (props) => { - const theme = props.theme || AmplifyTheme; - return beforeAfter( - - {props.children} - - ); -}; - -export const FormRow = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.formRow); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const RadioRow = (props) => { - const id = props.id || '_' + props.value; - const theme = props.theme || AmplifyTheme; - return ( - - - - - ); -}; - -export const Radio = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.radio); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - - ); -}; - -export const InputRow = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.input); - const p = JS.objectLessAttributes(props, 'theme'); - return ( - - {beforeAfter( - - )} - - ); -}; - -export const Input = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.input); - const p = JS.objectLessAttributes(props, 'theme'); - return ( - - ); -}; - -export const SelectInput = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.selectInput); - return ( -
- {props.children} -
- ); -}; - -export const FormField = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.formField); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const Button = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.button); - const disabled = props.disabled || false; - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - - ); -}; - -export const PhotoPickerButton = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.photoPickerButton); - const p = JS.objectLessAttributes(props, 'theme'); - return ( - - ); -}; - -export const SignInButton = (props) => { - const theme = props.theme || AmplifyTheme; - const styles = Object.assign({}, theme.signInButton, theme[props.variant]); - const p = JS.objectLessAttributes(props, 'theme'); - - return beforeAfter( - - ); -}; - -export const SignInButtonIcon = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.signInButtonIcon); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - - {props.children} - - ); -}; - -export const SignInButtonContent = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.signInButtonContent); - return beforeAfter( - - {props.children} - - ); -}; - -export const Link = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.a); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - {props.children} - ); -}; - -export const Label = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.label); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - - ); -}; - -export const Hint = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.hint); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const InputLabel = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.inputLabel); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const NavBar = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.navBar); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const Nav = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.nav); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const NavRight = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.navRight); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const NavItem = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.navItem); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const NavButton = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.navButton); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - - ); -}; - -export const Toast = (props) => { - const { onClose } = props; - const theme = props.theme || AmplifyTheme; - - return ( -
- {props.children} - -
- ); +export const Container = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.container); + const p = JS.objectLessAttributes(props, 'theme'); + + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const FormContainer = props => { + const theme = props.theme || AmplifyTheme; + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const FormSection = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.formSection); + return ( + + {beforeAfter( +
+ {props.children} +
+ )} +
+ ); +}; + +export const SectionHeader = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.sectionHeader); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ + {props.children} + {props.hint && ( +
{props.hint}
+ )} +
+
+ ); +}; + +export const SectionHeaderContent = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.sectionHeaderContent); + return beforeAfter( + + {props.children} + + ); +}; + +export const SectionFooter = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.sectionFooter); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const SectionFooterPrimaryContent = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.sectionFooterPrimaryContent); + return beforeAfter( + + {props.children} + + ); +}; + +export const SectionFooterSecondaryContent = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.sectionFooterSecondaryContent); + return beforeAfter( + + {props.children} + + ); +}; + +export const SectionBody = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.sectionBody); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const ActionRow = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.actionRow); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const Strike = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.strike); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const StrikeContent = props => { + const theme = props.theme || AmplifyTheme; + return beforeAfter( + + {props.children} + + ); +}; + +export const FormRow = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.formRow); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const RadioRow = props => { + const id = props.id || '_' + props.value; + const theme = props.theme || AmplifyTheme; + return ( + + + + + ); +}; + +export const Radio = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.radio); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + ); +}; + +export const InputRow = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.input); + const p = JS.objectLessAttributes(props, 'theme'); + return ( + + {beforeAfter()} + + ); +}; + +export const Input = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.input); + const p = JS.objectLessAttributes(props, 'theme'); + return ; +}; + +export const SelectInput = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.selectInput); + return ( +
+ {props.children} +
+ ); +}; + +export const FormField = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.formField); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const Button = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.button); + const disabled = props.disabled || false; + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + ); +}; + +export const PhotoPickerButton = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.photoPickerButton); + const p = JS.objectLessAttributes(props, 'theme'); + return ( + + ); +}; + +export const SignInButton = props => { + const theme = props.theme || AmplifyTheme; + const styles = Object.assign({}, theme.signInButton, theme[props.variant]); + const p = JS.objectLessAttributes(props, 'theme'); + + return beforeAfter( + + ); +}; + +export const SignInButtonIcon = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.signInButtonIcon); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + {props.children} + + ); +}; + +export const SignInButtonContent = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.signInButtonContent); + return beforeAfter( + + {props.children} + + ); +}; + +export const Link = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.a); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} + + ); +}; + +export const Label = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.label); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + ); +}; + +export const Hint = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.hint); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const InputLabel = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.inputLabel); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const NavBar = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.navBar); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const Nav = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.nav); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const NavRight = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.navRight); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const NavItem = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.navItem); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const NavButton = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.navButton); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + ); +}; + +export const Toast = props => { + const { onClose } = props; + const theme = props.theme || AmplifyTheme; + + return ( +
+ {props.children} + +
+ ); }; Toast.defaultProps = { - onClose: () => void(0) -}; - -export const PhotoPlaceholder = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.photoPlaceholder); - return ( -
-
- - - - - -
-
- ); -}; - -export const beforeAfter = (el) => { - const style = el.props.style || {}; - const { before, after } = style; - if (!before && !after) { return el; } - - return ( - - {before ? {before.content} : null} - {el} - {after ? {after.content} : null} - - ); + onClose: () => void 0, +}; + +export const PhotoPlaceholder = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.photoPlaceholder); + return ( +
+
+ + + + + +
+
+ ); +}; + +export const beforeAfter = el => { + const style = el.props.style || {}; + const { before, after } = style; + if (!before && !after) { + return el; + } + + return ( + + {before ? {before.content} : null} + {el} + {after ? {after.content} : null} + + ); }; export const propStyle = (props, themeStyle) => { - const { id, style } = props; - const styl = Object.assign({}, style, themeStyle); - if (!id) { return styl; } - - const selector = '#' + id; - Object.assign(styl, styl[selector]); - return styl; + const { id, style } = props; + const styl = Object.assign({}, style, themeStyle); + if (!id) { + return styl; + } + + const selector = '#' + id; + Object.assign(styl, styl[selector]); + return styl; }; diff --git a/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Theme-Sample.jsx b/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Theme-Sample.jsx index 15ad3b4e88e..29d73c2fb29 100644 --- a/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Theme-Sample.jsx +++ b/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Theme-Sample.jsx @@ -11,225 +11,225 @@ */ export const Container = { - fontFamily: `"Amazon Ember", "Helvetica Neue", sans-serif`, - fontWeight: '400', + fontFamily: `"Amazon Ember", "Helvetica Neue", sans-serif`, + fontWeight: '400', }; export const FormContainer = { - textAlign: 'center', - marginTop: '20px', - margin: '5% auto 50px', + textAlign: 'center', + marginTop: '20px', + margin: '5% auto 50px', }; export const FormSection = { - position: 'relative', - marginBottom: '20px', - backgroundColor: '#fff', - padding: '35px 40px', - textAlign: 'left', - display: 'inline-block', - minWidth: '380px', - borderRadius: '6px', - boxShadow: '1px 1px 4px 0 rgba(0,0,0,0.15)' + position: 'relative', + marginBottom: '20px', + backgroundColor: '#fff', + padding: '35px 40px', + textAlign: 'left', + display: 'inline-block', + minWidth: '380px', + borderRadius: '6px', + boxShadow: '1px 1px 4px 0 rgba(0,0,0,0.15)', }; export const FormField = { - marginBottom: '22px', + marginBottom: '22px', }; export const SectionHeader = { - color:'#152939', - marginBottom: '30px', - fontSize: '18px', - fontWeight: '500', + color: '#152939', + marginBottom: '30px', + fontSize: '18px', + fontWeight: '500', }; export const SectionBody = { - marginBottom: '30px', + marginBottom: '30px', }; export const SectionFooter = { - fontSize: '14px', - color: '#828282', - display: 'flex', - flexDirection: 'row-reverse', - alignItems: 'flex-start', + fontSize: '14px', + color: '#828282', + display: 'flex', + flexDirection: 'row-reverse', + alignItems: 'flex-start', }; export const SectionFooterPrimaryContent = { - marginLeft: 'auto' + marginLeft: 'auto', }; export const SectionFooterSecondaryContent = { - marginRight: 'auto', - alignSelf: 'center', + marginRight: 'auto', + alignSelf: 'center', }; export const Input = { - display: 'block', - width: '100%', - padding: '16px', - fontSize: '14px', - fontFamily: `"Amazon Ember", Arial`, - color: '#152939', - backgroundColor: '#fff', - backgroundImage: 'none', - border: '1px solid #C4C4C4', - borderRadius: '3px', - boxSizing: 'border-box', - marginBottom: '10px', + display: 'block', + width: '100%', + padding: '16px', + fontSize: '14px', + fontFamily: `"Amazon Ember", Arial`, + color: '#152939', + backgroundColor: '#fff', + backgroundImage: 'none', + border: '1px solid #C4C4C4', + borderRadius: '3px', + boxSizing: 'border-box', + marginBottom: '10px', }; export const Button = { - minWidth: '153px', - display: 'inline-block', - marginBottom: '0', - fontSize: '12px', - fontWeight: 400, - lineHeight: '1.42857143', - textAlign: 'center', - whiteSpace: 'nowrap', - verticalAlign: 'middle', - touchAction: 'manipulation', - cursor: 'pointer', - userSelect: 'none', - backgroundImage: 'none', - color: '#fff', - backgroundColor: '#FF9900', - borderColor: '#ccc', - textTransform: 'uppercase', - padding: '14px 0', - letterSpacing: '1.1px', - border: 'none', + minWidth: '153px', + display: 'inline-block', + marginBottom: '0', + fontSize: '12px', + fontWeight: 400, + lineHeight: '1.42857143', + textAlign: 'center', + whiteSpace: 'nowrap', + verticalAlign: 'middle', + touchAction: 'manipulation', + cursor: 'pointer', + userSelect: 'none', + backgroundImage: 'none', + color: '#fff', + backgroundColor: '#FF9900', + borderColor: '#ccc', + textTransform: 'uppercase', + padding: '14px 0', + letterSpacing: '1.1px', + border: 'none', }; export const SignInButton = { - position: 'relative', - width: '100%', - borderRadius: '4px', - marginBottom: '10px', - cursor: 'pointer', - padding: 0, - fontFamily: 'Amazon Ember', - color: '#fff', - fontSize: '14px', - '#google_signin_btn': { - backgroundColor: '#4285F4', - fontFamily: 'Roboto', - border: '1px solid #4285F4' - }, - '#facebook_signin_btn': { - backgroundColor: '#4267B2', - borderColor: '#4267B2', - }, - '#amazon_signin_btn': { - backgroundColor: '#FF9900', - border: 'none', - } + position: 'relative', + width: '100%', + borderRadius: '4px', + marginBottom: '10px', + cursor: 'pointer', + padding: 0, + fontFamily: 'Amazon Ember', + color: '#fff', + fontSize: '14px', + '#google_signin_btn': { + backgroundColor: '#4285F4', + fontFamily: 'Roboto', + border: '1px solid #4285F4', + }, + '#facebook_signin_btn': { + backgroundColor: '#4267B2', + borderColor: '#4267B2', + }, + '#amazon_signin_btn': { + backgroundColor: '#FF9900', + border: 'none', + }, }; export const SignInButtonIcon = { - position: 'absolute', - left: 0, - '#google_signin_btn_icon': { - backgroundColor: '#fff', - borderRadius: '4px 0 0 4px', - height: '30px', - width: '30px', - padding: '11px', - }, - '#facebook_signin_btn_icon': { - height: '33px', - width: '18px', - padding: '10px 14px' - }, - '#amazon_signin_btn_icon': { - padding: '10px', - height: '32px', - width: '32px', - } + position: 'absolute', + left: 0, + '#google_signin_btn_icon': { + backgroundColor: '#fff', + borderRadius: '4px 0 0 4px', + height: '30px', + width: '30px', + padding: '11px', + }, + '#facebook_signin_btn_icon': { + height: '33px', + width: '18px', + padding: '10px 14px', + }, + '#amazon_signin_btn_icon': { + padding: '10px', + height: '32px', + width: '32px', + }, }; export const SignInButtonContent = { - display: 'block', - padding: '18px 0', - whiteSpace: 'nowrap', - overflow: 'hidden', - textOverflow: 'ellipsis', - textAlign: 'center', + display: 'block', + padding: '18px 0', + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', + textAlign: 'center', }; export const Strike = { - width: '100%', - textAlign: 'center', - borderBottom: '1px solid #bbb', - lineHeight: '0.1em', - margin: '32px 0', - color: '#828282', + width: '100%', + textAlign: 'center', + borderBottom: '1px solid #bbb', + lineHeight: '0.1em', + margin: '32px 0', + color: '#828282', }; export const StrikeContent = { - background: '#fff', - padding: '0 25px', - fontSize: '14px', - fontWeight: '500', + background: '#fff', + padding: '0 25px', + fontSize: '14px', + fontWeight: '500', }; export const ActionRow = { - marginBottom: '15px' + marginBottom: '15px', }; export const FormRow = { - marginBottom: '12px' + marginBottom: '12px', }; export const A = { - color: '#FF9900', - cursor: 'pointer', + color: '#FF9900', + cursor: 'pointer', }; export const Hint = { - color: '#828282', - fontSize: '12px', + color: '#828282', + fontSize: '12px', }; export const Radio = { - marginRight: '18px', - verticalAlign: 'bottom', + marginRight: '18px', + verticalAlign: 'bottom', }; export const InputLabel = { - color: '#152939', - fontSize: '14px', - marginBottom: '8px', + color: '#152939', + fontSize: '14px', + marginBottom: '8px', }; const Bootstrap = { - container: Container, - formContainer: FormContainer, - formSection: FormSection, - formField: FormField, - - sectionHeader: SectionHeader, - sectionBody: SectionBody, - sectionFooter: SectionFooter, - sectionFooterPrimaryContent: SectionFooterPrimaryContent, - sectionFooterSecondaryContent: SectionFooterSecondaryContent, - - input: Input, - button: Button, - signInButton: SignInButton, - signInButtonIcon: SignInButtonIcon, - signInButtonContent: SignInButtonContent, - formRow: FormRow, - strike: Strike, - strikeContent: StrikeContent, - actionRow: ActionRow, - a: A, - - hint: Hint, - radio: Radio, - inputLabel: InputLabel, + container: Container, + formContainer: FormContainer, + formSection: FormSection, + formField: FormField, + + sectionHeader: SectionHeader, + sectionBody: SectionBody, + sectionFooter: SectionFooter, + sectionFooterPrimaryContent: SectionFooterPrimaryContent, + sectionFooterSecondaryContent: SectionFooterSecondaryContent, + + input: Input, + button: Button, + signInButton: SignInButton, + signInButtonIcon: SignInButtonIcon, + signInButtonContent: SignInButtonContent, + formRow: FormRow, + strike: Strike, + strikeContent: StrikeContent, + actionRow: ActionRow, + a: A, + + hint: Hint, + radio: Radio, + inputLabel: InputLabel, }; export default Bootstrap; diff --git a/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Theme.jsx b/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Theme.jsx index e53fa83b305..bfe223e292c 100644 --- a/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Theme.jsx +++ b/packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Theme.jsx @@ -48,46 +48,46 @@ export const NavItem = {}; export const NavButton = {}; const AmplifyTheme = { - container: Container, - formContainer: FormContainer, - formSection: FormSection, - formField: FormField, + container: Container, + formContainer: FormContainer, + formSection: FormSection, + formField: FormField, - sectionHeader: SectionHeader, - sectionBody: SectionBody, - sectionFooter: SectionFooter, - sectionFooterPrimaryContent: SectionFooterPrimaryContent, - sectionFooterSecondaryContent: SectionFooterSecondaryContent, + sectionHeader: SectionHeader, + sectionBody: SectionBody, + sectionFooter: SectionFooter, + sectionFooterPrimaryContent: SectionFooterPrimaryContent, + sectionFooterSecondaryContent: SectionFooterSecondaryContent, - input: Input, - button: Button, - photoPickerButton: PhotoPickerButton, - photoPlaceholder: PhotoPlaceholder, - signInButton: SignInButton, - signInButtonIcon: SignInButtonIcon, - signInButtonContent: SignInButtonContent, - amazonSignInButton: AmazonSignInButton, - facebookSignInButton: FacebookSignInButton, - googleSignInButton: GoogleSignInButton, - oAuthSignInButton: OAuthSignInButton, + input: Input, + button: Button, + photoPickerButton: PhotoPickerButton, + photoPlaceholder: PhotoPlaceholder, + signInButton: SignInButton, + signInButtonIcon: SignInButtonIcon, + signInButtonContent: SignInButtonContent, + amazonSignInButton: AmazonSignInButton, + facebookSignInButton: FacebookSignInButton, + googleSignInButton: GoogleSignInButton, + oAuthSignInButton: OAuthSignInButton, - formRow: FormRow, - strike: Strike, - strikeContent: StrikeContent, - actionRow: ActionRow, - a: A, + formRow: FormRow, + strike: Strike, + strikeContent: StrikeContent, + actionRow: ActionRow, + a: A, - hint: Hint, - radio: Radio, - label: Label, - inputLabel: InputLabel, - toast: Toast, - - navBar: NavBar, - nav: Nav, - navRight: NavRight, - navItem: NavItem, - navButton: NavButton + hint: Hint, + radio: Radio, + label: Label, + inputLabel: InputLabel, + toast: Toast, + + navBar: NavBar, + nav: Nav, + navRight: NavRight, + navItem: NavItem, + navButton: NavButton, }; export default AmplifyTheme; diff --git a/packages/aws-amplify-react/src/Amplify-UI/data-test-attributes.js b/packages/aws-amplify-react/src/Amplify-UI/data-test-attributes.js index 124f9569215..0319edd571d 100644 --- a/packages/aws-amplify-react/src/Amplify-UI/data-test-attributes.js +++ b/packages/aws-amplify-react/src/Amplify-UI/data-test-attributes.js @@ -1,163 +1,162 @@ // Auth const signIn = { - section: 'sign-in-section', - headerSection: 'sign-in-header-section', - bodySection: 'sign-in-body-section', - footerSection: 'sign-in-footer-section', - usernameInput: 'username-input', - passwordInput: 'sign-in-password-input', - forgotPasswordLink: 'sign-in-forgot-password-link', - signInButton: 'sign-in-sign-in-button', - createAccountLink: 'sign-in-create-account-link', - signInError: 'authenticator-error', + section: 'sign-in-section', + headerSection: 'sign-in-header-section', + bodySection: 'sign-in-body-section', + footerSection: 'sign-in-footer-section', + usernameInput: 'username-input', + passwordInput: 'sign-in-password-input', + forgotPasswordLink: 'sign-in-forgot-password-link', + signInButton: 'sign-in-sign-in-button', + createAccountLink: 'sign-in-create-account-link', + signInError: 'authenticator-error', }; const signOut = { - button: 'sign-out-button', - section: 'sign-out-section', + button: 'sign-out-button', + section: 'sign-out-section', }; const signUp = { - section: 'sign-up-section', - headerSection: 'sign-up-header-section', - bodySection: 'sign-up-body-section', - nonPhoneNumberInput: 'sign-up-non-phone-number-input', - phoneNumberInput: 'sign-up-phone-number-input', - dialCodeSelect: 'sign-up-dial-code-select', - footerSection: 'sign-up-footer-section', - createAccountButton: 'sign-up-create-account-button', - signInLink: 'sign-up-sign-in-link', - signUpButton: 'sign-up-sign-up-button', - signInButton: 'sign-up-sign-in-button', - confirmButton: 'sign-up-confirm-button', + section: 'sign-up-section', + headerSection: 'sign-up-header-section', + bodySection: 'sign-up-body-section', + nonPhoneNumberInput: 'sign-up-non-phone-number-input', + phoneNumberInput: 'sign-up-phone-number-input', + dialCodeSelect: 'sign-up-dial-code-select', + footerSection: 'sign-up-footer-section', + createAccountButton: 'sign-up-create-account-button', + signInLink: 'sign-up-sign-in-link', + signUpButton: 'sign-up-sign-up-button', + signInButton: 'sign-up-sign-in-button', + confirmButton: 'sign-up-confirm-button', }; const verifyContact = { - section: 'verify-contact-section', - headerSection: 'verify-contact-header-section', - bodySection: 'verify-contact-body-section', - submitButton: 'verify-contact-submit-button', - verifyButton: 'verify-contact-verify-button', - skipLink: 'verify-contact-skip-link', + section: 'verify-contact-section', + headerSection: 'verify-contact-header-section', + bodySection: 'verify-contact-body-section', + submitButton: 'verify-contact-submit-button', + verifyButton: 'verify-contact-verify-button', + skipLink: 'verify-contact-skip-link', }; const TOTPSetup = { - component: 'totp-setup-component', + component: 'totp-setup-component', }; const requireNewPassword = { - section: 'require-new-password-section', - headerSection: 'require-new-password-header-section', - footerSection:'require-new-password-footer-section', - bodySection:'require-new-password-body-section', - newPasswordInput:'require-new-password-new-password-input', - backToSignInLink:'require-new-password-back-to-sign-in-link', - submitButton: 'require-new-password-submit-button', + section: 'require-new-password-section', + headerSection: 'require-new-password-header-section', + footerSection: 'require-new-password-footer-section', + bodySection: 'require-new-password-body-section', + newPasswordInput: 'require-new-password-new-password-input', + backToSignInLink: 'require-new-password-back-to-sign-in-link', + submitButton: 'require-new-password-submit-button', }; const loading = { - section: 'loading-secton', + section: 'loading-secton', }; const greetings = { - navBar: 'greetings-nav-bar', - nav: 'greetings-nav', - navRight: 'greetings-nav-right' + navBar: 'greetings-nav-bar', + nav: 'greetings-nav', + navRight: 'greetings-nav-right', }; -// TODO: Change Angular Component (Greeting) to match React Component (Greetings) +// TODO: Change Angular Component (Greeting) to match React Component (Greetings) const greeting = { - signOutButton: 'sign-out-button', - signOutLink: 'greeting-sign-out-link', - navRight: 'greetings-nav-right', + signOutButton: 'sign-out-button', + signOutLink: 'greeting-sign-out-link', + navRight: 'greetings-nav-right', }; const federatedSignIn = { - section: 'federated-sign-in-section', - bodySection: 'federated-sign-in-body-section', - signInButtons:'federated-sign-in-buttons', + section: 'federated-sign-in-section', + bodySection: 'federated-sign-in-body-section', + signInButtons: 'federated-sign-in-buttons', }; const confirmSignUp = { - section: 'confirm-sign-up-section', - headerSection: 'confirm-sign-up-header-section', - bodySection: 'confirm-sign-up-body-section', - usernameInput: 'confirm-sign-up-username-input', - confirmationCodeInput: 'confirm-sign-up-confirmation-code-input', - resendCodeLink: 'confirm-sign-up-resend-code-link', - confirmButton: 'confirm-sign-up-confirm-button', - backToSignInLink: 'confirm-sign-up-back-to-sign-in-link' + section: 'confirm-sign-up-section', + headerSection: 'confirm-sign-up-header-section', + bodySection: 'confirm-sign-up-body-section', + usernameInput: 'confirm-sign-up-username-input', + confirmationCodeInput: 'confirm-sign-up-confirmation-code-input', + resendCodeLink: 'confirm-sign-up-resend-code-link', + confirmButton: 'confirm-sign-up-confirm-button', + backToSignInLink: 'confirm-sign-up-back-to-sign-in-link', }; const confirmSignIn = { - section: 'confirm-sign-in-section', - headerSection: 'confirm-sign-in-header-section', - bodySection: 'confirm-sign-in-body-section', - codeInput: 'confirm-sign-in-code-input', - confirmButton: 'confirm-sign-in-confirm-button', - backToSignInLink: 'confirm-sign-in-back-to-sign-in-link', + section: 'confirm-sign-in-section', + headerSection: 'confirm-sign-in-header-section', + bodySection: 'confirm-sign-in-body-section', + codeInput: 'confirm-sign-in-code-input', + confirmButton: 'confirm-sign-in-confirm-button', + backToSignInLink: 'confirm-sign-in-back-to-sign-in-link', }; const setMFAComp = { - section: 'set-mfa-section', - headerSection: 'set-mfa-header-section', - bodySection: 'set-mfa-header-body-section', - smsInput: 'set-mfa-sms-input', - totpInput: 'set-mfa-totp-input', - noMfaInput: 'set-mfa-nomfa-input', - verificationCodeInput: 'set-mfa-verification-code-input', - setMfaButton: 'set-mfa-set-mfa-button', - verifyTotpTokenButton: 'set-mfa-verify-totp-token-button', - cancelButton: 'set-mfa-cancel-button', + section: 'set-mfa-section', + headerSection: 'set-mfa-header-section', + bodySection: 'set-mfa-header-body-section', + smsInput: 'set-mfa-sms-input', + totpInput: 'set-mfa-totp-input', + noMfaInput: 'set-mfa-nomfa-input', + verificationCodeInput: 'set-mfa-verification-code-input', + setMfaButton: 'set-mfa-set-mfa-button', + verifyTotpTokenButton: 'set-mfa-verify-totp-token-button', + cancelButton: 'set-mfa-cancel-button', }; const forgotPassword = { - section: 'forgot-password-section', - headerSection: 'forgot-password-header-section', - bodySection: 'forgot-password-body-section', - submitButton: 'forgot-password-submit-button', - sendCodeButton: 'forgot-password-send-code-button', - resendCodeLink: 'forgot-password-resend-code-link', - backToSignInLink: 'forgot-password-back-to-sign-in-link', - usernameInput: 'username-input', - codeInput: 'forgot-password-code-input', - newPasswordInput: 'forgot-password-new-password-input', + section: 'forgot-password-section', + headerSection: 'forgot-password-header-section', + bodySection: 'forgot-password-body-section', + submitButton: 'forgot-password-submit-button', + sendCodeButton: 'forgot-password-send-code-button', + resendCodeLink: 'forgot-password-resend-code-link', + backToSignInLink: 'forgot-password-back-to-sign-in-link', + usernameInput: 'username-input', + codeInput: 'forgot-password-code-input', + newPasswordInput: 'forgot-password-new-password-input', }; export const sumerianScene = { - container: 'sumerian-scene-container', - sumerianScene: 'sumerian-scene', - loading: 'sumerian-scene-loading', - loadingLogo: 'sumerian-scene-loading-logo', - loadingSceneName: 'sumerian-scene-loading-scene-name', - loadingBar: 'sumerian-scene-loading-bar', - errorText: 'sumerian-scene-error-text', - bar: 'sumerian-scene-bar', - actions: 'sumerian-scene-actions', + container: 'sumerian-scene-container', + sumerianScene: 'sumerian-scene', + loading: 'sumerian-scene-loading', + loadingLogo: 'sumerian-scene-loading-logo', + loadingSceneName: 'sumerian-scene-loading-scene-name', + loadingBar: 'sumerian-scene-loading-bar', + errorText: 'sumerian-scene-error-text', + bar: 'sumerian-scene-bar', + actions: 'sumerian-scene-actions', }; export const genericAttrs = { - usernameInput: 'username-input', - emailInput: 'email-input', - phoneNumberInput: 'phone-number-input', - dialCodeSelect: 'dial-code-select', + usernameInput: 'username-input', + emailInput: 'email-input', + phoneNumberInput: 'phone-number-input', + dialCodeSelect: 'dial-code-select', }; - export const auth = { - signIn, - signOut, - signUp, - verifyContact, - TOTPSetup, - requireNewPassword, - loading, - genericAttrs, - greetings, - greeting, - federatedSignIn, - confirmSignUp, - confirmSignIn, - setMFAComp, - forgotPassword, + signIn, + signOut, + signUp, + verifyContact, + TOTPSetup, + requireNewPassword, + loading, + genericAttrs, + greetings, + greeting, + federatedSignIn, + confirmSignUp, + confirmSignIn, + setMFAComp, + forgotPassword, }; diff --git a/packages/aws-amplify-react/src/AmplifyI18n.js b/packages/aws-amplify-react/src/AmplifyI18n.js index 650aaf1f3ae..152609dc591 100644 --- a/packages/aws-amplify-react/src/AmplifyI18n.js +++ b/packages/aws-amplify-react/src/AmplifyI18n.js @@ -12,218 +12,224 @@ */ const dict = { - 'de': { - 'Sign In': "Anmelden", - 'Sign Up': "Registrieren", - 'Sign Out': "Abmelden", - 'Sign in to your account': 'Melden Sie sich mit Ihrem Account an', - 'Username': "Benutzername", - 'Password': "Passwort", - 'Enter your username': "Geben Sie Ihren Benutzernamen ein", - 'Enter your password': "Geben Sie Ihr Passwort ein", - 'No account? ': "Kein Account? ", - 'Forget your password? ': 'Passwort vergessen? ', - 'Reset password': "Passwort zurücksetzen", - 'User does not exist': 'Dieser Benutzer existiert nicht', - 'User already exists': "Dieser Benutzer existiert bereits", - 'Incorrect username or password': "Falscher Benutzername oder falsches Passwort", - 'Invalid password format': "Ungültiges Passwort-Format", - 'Create account': "Hier registrieren", - 'Forgot Password': "Passwort vergessen", - 'Change Password': "Passwort ändern", - 'New Password': "Neues Passwort", - 'Email': "Email", - 'Phone Number': "Telefonnummer", - 'Confirm a Code': "Code bestätigen", - 'Confirm Sign In': "Anmeldung bestätigen", - 'Confirm Sign Up': "Registrierung bestätigen", - 'Back to Sign In': "Zurück zur Anmeldung", - 'Send Code': "Code senden", - 'Confirm': "Bestätigen", - 'Resend Code': "Code erneut senden", - 'Submit': "Abschicken", - 'Skip': "Überspringen", - 'Verify': "Verifizieren", - 'Verify Contact': "Kontakt verifizieren", - 'Code': "Code", - 'Confirmation Code': "Bestätigungs-Code", - 'Lost your code? ' : "Code verloren? ", - 'Account recovery requires verified contact information': - "Zurücksetzen des Account benötigt einen verifizierten Account", - 'Invalid phone number format': - `Ungültiges Telefonummern-Format. + de: { + 'Sign In': 'Anmelden', + 'Sign Up': 'Registrieren', + 'Sign Out': 'Abmelden', + 'Sign in to your account': 'Melden Sie sich mit Ihrem Account an', + Username: 'Benutzername', + Password: 'Passwort', + 'Enter your username': 'Geben Sie Ihren Benutzernamen ein', + 'Enter your password': 'Geben Sie Ihr Passwort ein', + 'No account? ': 'Kein Account? ', + 'Forget your password? ': 'Passwort vergessen? ', + 'Reset password': 'Passwort zurücksetzen', + 'User does not exist': 'Dieser Benutzer existiert nicht', + 'User already exists': 'Dieser Benutzer existiert bereits', + 'Incorrect username or password': + 'Falscher Benutzername oder falsches Passwort', + 'Invalid password format': 'Ungültiges Passwort-Format', + 'Create account': 'Hier registrieren', + 'Forgot Password': 'Passwort vergessen', + 'Change Password': 'Passwort ändern', + 'New Password': 'Neues Passwort', + Email: 'Email', + 'Phone Number': 'Telefonnummer', + 'Confirm a Code': 'Code bestätigen', + 'Confirm Sign In': 'Anmeldung bestätigen', + 'Confirm Sign Up': 'Registrierung bestätigen', + 'Back to Sign In': 'Zurück zur Anmeldung', + 'Send Code': 'Code senden', + Confirm: 'Bestätigen', + 'Resend Code': 'Code erneut senden', + Submit: 'Abschicken', + Skip: 'Überspringen', + Verify: 'Verifizieren', + 'Verify Contact': 'Kontakt verifizieren', + Code: 'Code', + 'Confirmation Code': 'Bestätigungs-Code', + 'Lost your code? ': 'Code verloren? ', + 'Account recovery requires verified contact information': + 'Zurücksetzen des Account benötigt einen verifizierten Account', + 'Invalid phone number format': `Ungültiges Telefonummern-Format. Benutze eine Nummer im Format: +12345678900`, - 'Create Account': "Account erstellen", - 'Have an account? ': "Schon registriert? ", - 'Sign in': "Anmelden", - 'Create a new account': "Erstelle einen neuen Account", - 'Reset your password': "Zurücksetzen des Passworts", - 'An account with the given email already exists.': "Ein Account mit dieser Email existiert bereits.", - 'Username cannot be empty': "Benutzername darf nicht leer sein", - 'Password attempts exceeded': "Die maximale Anzahl der fehlerhaften Anmeldeversuche wurde erreicht" - }, - 'fr': { - 'Sign In': "Se connecter", - 'Sign Up': "S'inscrire", - 'Sign Out': "Déconnexion", - 'Forgot Password': "Mot de passe oublié", - 'Username': "Nom d'utilisateur", - 'Password': "Mot de passe", - 'Change Password': "Changer le mot de passe", - 'New Password': "nouveau mot de passe", - 'Email': "Email", - 'Phone Number': "Numéro de téléphone", - 'Confirm a Code': "Confirmer un code", - 'Confirm Sign In': "Confirmer la connexion", - 'Confirm Sign Up': "Confirmer l'inscription", - 'Back to Sign In': "Retour à la connexion", - 'Send Code': "Envoyer le code", - 'Confirm': "Confirmer", - 'Resend a Code': "Renvoyer un code", - 'Submit': "Soumettre", - 'Skip': "Sauter", - 'Verify': "Vérifier", - 'Verify Contact': "Vérifier le contact", - 'Code': "Code", - 'Account recovery requires verified contact information': - "La récupération du compte nécessite des informations de contact vérifiées", + 'Create Account': 'Account erstellen', + 'Have an account? ': 'Schon registriert? ', + 'Sign in': 'Anmelden', + 'Create a new account': 'Erstelle einen neuen Account', + 'Reset your password': 'Zurücksetzen des Passworts', + 'An account with the given email already exists.': + 'Ein Account mit dieser Email existiert bereits.', + 'Username cannot be empty': 'Benutzername darf nicht leer sein', + 'Password attempts exceeded': + 'Die maximale Anzahl der fehlerhaften Anmeldeversuche wurde erreicht', + }, + fr: { + 'Sign In': 'Se connecter', + 'Sign Up': "S'inscrire", + 'Sign Out': 'Déconnexion', + 'Forgot Password': 'Mot de passe oublié', + Username: "Nom d'utilisateur", + Password: 'Mot de passe', + 'Change Password': 'Changer le mot de passe', + 'New Password': 'nouveau mot de passe', + Email: 'Email', + 'Phone Number': 'Numéro de téléphone', + 'Confirm a Code': 'Confirmer un code', + 'Confirm Sign In': 'Confirmer la connexion', + 'Confirm Sign Up': "Confirmer l'inscription", + 'Back to Sign In': 'Retour à la connexion', + 'Send Code': 'Envoyer le code', + Confirm: 'Confirmer', + 'Resend a Code': 'Renvoyer un code', + Submit: 'Soumettre', + Skip: 'Sauter', + Verify: 'Vérifier', + 'Verify Contact': 'Vérifier le contact', + Code: 'Code', + 'Account recovery requires verified contact information': + 'La récupération du compte nécessite des informations de contact vérifiées', - 'User does not exist': "L'utilisateur n'existe pas", - 'User already exists': "L'utilisateur existe déjà", - 'Incorrect username or password': "identifiant ou mot de passe incorrect", - 'Invalid password format': "format de mot de passe invalide", - 'Invalid phone number format': - `Format de numéro de téléphone invalide. + 'User does not exist': "L'utilisateur n'existe pas", + 'User already exists': "L'utilisateur existe déjà", + 'Incorrect username or password': 'identifiant ou mot de passe incorrect', + 'Invalid password format': 'format de mot de passe invalide', + 'Invalid phone number format': `Format de numéro de téléphone invalide. Veuillez utiliser un format de numéro de téléphone du +12345678900`, - 'Sign in to your account': "Connectez-vous à votre compte", - 'Forget your password? ': "Mot de passe oublié ? ", - 'Reset password': "Réinitialisez votre mot de passe", - 'No account? ': "Pas de compte ? ", - 'Create account': "Créer un compte", - 'Create Account': "Créer un compte", - 'Have an account? ': "Déjà un compte ? ", - 'Sign in': "Se connecter", - 'Create a new account': "Créer un nouveau compte", - 'Reset your password': "Réinitialisez votre mot de passe", - 'Enter your username': "Saisissez votre nom d'utilisateur", - 'Enter your password': "Saisissez votre mot de passe", - 'An account with the given email already exists.': "Un utilisateur avec cette adresse email existe déjà.", - 'Username cannot be empty': "Le nom d'utilisateur doit être renseigné" - }, + 'Sign in to your account': 'Connectez-vous à votre compte', + 'Forget your password? ': 'Mot de passe oublié ? ', + 'Reset password': 'Réinitialisez votre mot de passe', + 'No account? ': 'Pas de compte ? ', + 'Create account': 'Créer un compte', + 'Create Account': 'Créer un compte', + 'Have an account? ': 'Déjà un compte ? ', + 'Sign in': 'Se connecter', + 'Create a new account': 'Créer un nouveau compte', + 'Reset your password': 'Réinitialisez votre mot de passe', + 'Enter your username': "Saisissez votre nom d'utilisateur", + 'Enter your password': 'Saisissez votre mot de passe', + 'An account with the given email already exists.': + 'Un utilisateur avec cette adresse email existe déjà.', + 'Username cannot be empty': "Le nom d'utilisateur doit être renseigné", + }, - 'es': { - 'Sign In': "Registrarse", - 'Sign Up': "Regístrate", - 'Sign Out': "Desconectar", - 'Forgot Password': "Se te olvidó tu contraseña", - 'Username': "Nombre de usuario", - 'Password': "Contraseña", - 'Change Password': "Cambia la contraseña", - 'New Password': "Nueva contraseña", - 'Email': "Email", - 'Phone Number': "Número de teléfono", - 'Confirm a Code': "Confirmar un código", - 'Confirm Sign In': "Confirmar inicio de sesión", - 'Confirm Sign Up': "Confirmar Registrarse", - 'Back to Sign In': "Volver a Iniciar sesión", - 'Send Code': "Enviar código", - 'Confirm': "Confirmar", - 'Resend a Code': "Reenviar un código", - 'Submit': "Enviar", - 'Skip': "Omitir", - 'Verify': "Verificar", - 'Verify Contact': "Verificar contacto", - 'Code': "Código", - 'Account recovery requires verified contact information': - "La recuperación de la cuenta requiere información de contacto verificada", + es: { + 'Sign In': 'Registrarse', + 'Sign Up': 'Regístrate', + 'Sign Out': 'Desconectar', + 'Forgot Password': 'Se te olvidó tu contraseña', + Username: 'Nombre de usuario', + Password: 'Contraseña', + 'Change Password': 'Cambia la contraseña', + 'New Password': 'Nueva contraseña', + Email: 'Email', + 'Phone Number': 'Número de teléfono', + 'Confirm a Code': 'Confirmar un código', + 'Confirm Sign In': 'Confirmar inicio de sesión', + 'Confirm Sign Up': 'Confirmar Registrarse', + 'Back to Sign In': 'Volver a Iniciar sesión', + 'Send Code': 'Enviar código', + Confirm: 'Confirmar', + 'Resend a Code': 'Reenviar un código', + Submit: 'Enviar', + Skip: 'Omitir', + Verify: 'Verificar', + 'Verify Contact': 'Verificar contacto', + Code: 'Código', + 'Account recovery requires verified contact information': + 'La recuperación de la cuenta requiere información de contacto verificada', - 'User does not exist': "el usuario no existe", - 'User already exists': "El usuario ya existe", - 'Incorrect username or password': "Nombre de usuario o contraseña incorrecta", - 'Invalid password format': "Formato de contraseña inválido", - 'Invalid phone number format': - `Formato de número de teléfono inválido. -Utilice el formato de número de teléfono +12345678900` - }, - 'it': { - "Account recovery requires verified contact information": "Ripristino del conto richiede un account verificati", - "An account with the given email already exists.": "Un account con questa email esiste già.", - "Back to Sign In": "Torna alla Accesso", - "Change Password": "Cambia la password", - "Code": "Codice", - "Confirm": "Conferma", - "Confirm Sign In": "Conferma di applicazione", - "Confirm Sign Up": "Registrazione Conferma", - "Confirm a Code": "Codice Conferma", - "Confirmation Code": "Codice di verifica", - "Create Account": "Crea account", - "Create a new account": "Creare un nuovo account", - "Create account": "Registrati", - "Email": "E-mail", - "Enter your password": "Inserire la password", - "Enter your username": "Inserisci il tuo nome utente", - "Forget your password?" : "Password dimenticata?", - "Forgot Password": "Password dimenticata", - "Have an account? ": "Già registrato?", - "Incorrect username or password": "Nome utente o password errati", - "Invalid password format": "Formato della password non valido", - "Invalid phone number format": "Utilizzo non valido Telefonummern formattare un numero nel formato :. 12.345.678,9 mille", - "Lost your code?" : "Perso codice?", - "New Password": "Nuova password", - "No account? ": "Nessun account?", - "Password": "Password", - "Password attempts exceeded": "Il numero massimo di tentativi di accesso falliti è stato raggiunto", - "Phone Number": "Numero di telefono", - "Resend Code": "Codice Rispedisci", - "Reset password": "Ripristina password", - "Reset your password": "Resetta password", - "Send Code": "Invia codice", - "Sign In": "Accesso", - "Sign Out": "Esci", - "Sign Up": "Iscriviti", - "Sign in": "Accesso", - "Sign in to your account": "Accedi con il tuo account a", - "Skip": "Salta", - "Submit": "Sottoscrivi", - "User already exists": "Questo utente esiste già", - "User does not exist": "Questo utente non esiste", - "Username": "Nome utente", - "Username cannot be empty": "Nome utente non può essere vuoto", - "Verify": "Verifica", - "Verify Contact": "Contatto verifica" - }, - 'zh': { - 'Sign In': "登录", - 'Sign Up': "注册", - 'Sign Out': "退出", - 'Forgot Password': "忘记密码", - 'Username': "用户名", - 'Password': "密码", - 'Change Password': "改变密码", - 'New Password': "新密码", - 'Email': "邮箱", - 'Phone Number': "电话", - 'Confirm a Code': "确认码", - 'Confirm Sign In': "确认登录", - 'Confirm Sign Up': "确认注册", - 'Back to Sign In': "回到登录", - 'Send Code': "发送确认码", - 'Confirm': "确认", - 'Resend a Code': "重发确认码", - 'Submit': "提交", - 'Skip': "跳过", - 'Verify': "验证", - 'Verify Contact': "验证联系方式", - 'Code': "确认码", - 'Account recovery requires verified contact information': - "账户恢复需要验证过的联系方式", + 'User does not exist': 'el usuario no existe', + 'User already exists': 'El usuario ya existe', + 'Incorrect username or password': + 'Nombre de usuario o contraseña incorrecta', + 'Invalid password format': 'Formato de contraseña inválido', + 'Invalid phone number format': `Formato de número de teléfono inválido. +Utilice el formato de número de teléfono +12345678900`, + }, + it: { + 'Account recovery requires verified contact information': + 'Ripristino del conto richiede un account verificati', + 'An account with the given email already exists.': + 'Un account con questa email esiste già.', + 'Back to Sign In': 'Torna alla Accesso', + 'Change Password': 'Cambia la password', + Code: 'Codice', + Confirm: 'Conferma', + 'Confirm Sign In': 'Conferma di applicazione', + 'Confirm Sign Up': 'Registrazione Conferma', + 'Confirm a Code': 'Codice Conferma', + 'Confirmation Code': 'Codice di verifica', + 'Create Account': 'Crea account', + 'Create a new account': 'Creare un nuovo account', + 'Create account': 'Registrati', + Email: 'E-mail', + 'Enter your password': 'Inserire la password', + 'Enter your username': 'Inserisci il tuo nome utente', + 'Forget your password?': 'Password dimenticata?', + 'Forgot Password': 'Password dimenticata', + 'Have an account? ': 'Già registrato?', + 'Incorrect username or password': 'Nome utente o password errati', + 'Invalid password format': 'Formato della password non valido', + 'Invalid phone number format': + 'Utilizzo non valido Telefonummern formattare un numero nel formato :. 12.345.678,9 mille', + 'Lost your code?': 'Perso codice?', + 'New Password': 'Nuova password', + 'No account? ': 'Nessun account?', + Password: 'Password', + 'Password attempts exceeded': + 'Il numero massimo di tentativi di accesso falliti è stato raggiunto', + 'Phone Number': 'Numero di telefono', + 'Resend Code': 'Codice Rispedisci', + 'Reset password': 'Ripristina password', + 'Reset your password': 'Resetta password', + 'Send Code': 'Invia codice', + 'Sign In': 'Accesso', + 'Sign Out': 'Esci', + 'Sign Up': 'Iscriviti', + 'Sign in': 'Accesso', + 'Sign in to your account': 'Accedi con il tuo account a', + Skip: 'Salta', + Submit: 'Sottoscrivi', + 'User already exists': 'Questo utente esiste già', + 'User does not exist': 'Questo utente non esiste', + Username: 'Nome utente', + 'Username cannot be empty': 'Nome utente non può essere vuoto', + Verify: 'Verifica', + 'Verify Contact': 'Contatto verifica', + }, + zh: { + 'Sign In': '登录', + 'Sign Up': '注册', + 'Sign Out': '退出', + 'Forgot Password': '忘记密码', + Username: '用户名', + Password: '密码', + 'Change Password': '改变密码', + 'New Password': '新密码', + Email: '邮箱', + 'Phone Number': '电话', + 'Confirm a Code': '确认码', + 'Confirm Sign In': '确认登录', + 'Confirm Sign Up': '确认注册', + 'Back to Sign In': '回到登录', + 'Send Code': '发送确认码', + Confirm: '确认', + 'Resend a Code': '重发确认码', + Submit: '提交', + Skip: '跳过', + Verify: '验证', + 'Verify Contact': '验证联系方式', + Code: '确认码', + 'Account recovery requires verified contact information': + '账户恢复需要验证过的联系方式', - 'User does not exist': "用户不存在", - 'User already exists': "用户已经存在", - 'Incorrect username or password': "用户名或密码错误", - 'Invalid password format': "密码格式错误", - 'Invalid phone number format': "电话格式错误,请使用格式 +12345678900" - } + 'User does not exist': '用户不存在', + 'User already exists': '用户已经存在', + 'Incorrect username or password': '用户名或密码错误', + 'Invalid password format': '密码格式错误', + 'Invalid phone number format': '电话格式错误,请使用格式 +12345678900', + }, }; export default dict; diff --git a/packages/aws-amplify-react/src/AmplifyMessageMap.js b/packages/aws-amplify-react/src/AmplifyMessageMap.js index 84a084eee22..c9bf96c4f85 100644 --- a/packages/aws-amplify-react/src/AmplifyMessageMap.js +++ b/packages/aws-amplify-react/src/AmplifyMessageMap.js @@ -14,25 +14,25 @@ import { I18n } from '@aws-amplify/core'; export const MapEntries = [ - ['User does not exist', /user.*not.*exist/i], - ['User already exists', /user.*already.*exist/i], - ['Incorrect username or password', /incorrect.*username.*password/i], - ['Invalid password format', /validation.*password/i], - [ - 'Invalid phone number format', - /invalid.*phone/i, - 'Invalid phone number format. Please use a phone number format of +12345678900' - ] + ['User does not exist', /user.*not.*exist/i], + ['User already exists', /user.*already.*exist/i], + ['Incorrect username or password', /incorrect.*username.*password/i], + ['Invalid password format', /validation.*password/i], + [ + 'Invalid phone number format', + /invalid.*phone/i, + 'Invalid phone number format. Please use a phone number format of +12345678900', + ], ]; export default function AmplifyMessageMap(message) { - const match = MapEntries.filter(entry => entry[1].test(message)); - if (match.length === 0) { - return message; - } + const match = MapEntries.filter(entry => entry[1].test(message)); + if (match.length === 0) { + return message; + } - const entry = match[0]; - const msg = entry.length > 2? entry[2] : entry[0]; + const entry = match[0]; + const msg = entry.length > 2 ? entry[2] : entry[0]; - return I18n.get(entry[0], msg); + return I18n.get(entry[0], msg); } diff --git a/packages/aws-amplify-react/src/AmplifyTheme.jsx b/packages/aws-amplify-react/src/AmplifyTheme.jsx index 0af64a64731..f1506bb5f45 100644 --- a/packages/aws-amplify-react/src/AmplifyTheme.jsx +++ b/packages/aws-amplify-react/src/AmplifyTheme.jsx @@ -11,7 +11,7 @@ * and limitations under the License. */ export const Container = { - fontFamily: `-apple-system, + fontFamily: `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, @@ -21,308 +21,308 @@ export const Container = { "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`, - fontWeight: '400', - lineHeight: '1.5', - color: '#212529', - textAlign: 'left', - paddingLeft: '15px', - paddingRight: '15px' + fontWeight: '400', + lineHeight: '1.5', + color: '#212529', + textAlign: 'left', + paddingLeft: '15px', + paddingRight: '15px', }; export const NavBar = { - position: 'relative', - border: '1px solid transparent', - borderColor: '#e7e7e7' + position: 'relative', + border: '1px solid transparent', + borderColor: '#e7e7e7', }; export const NavRight = { - textAlign: 'right' + textAlign: 'right', }; export const Nav = { - margin: '7.5px' + margin: '7.5px', }; export const NavItem = { - display: 'inline-block', - padding: '10px 5px', - lineHeight: '20px' + display: 'inline-block', + padding: '10px 5px', + lineHeight: '20px', }; export const NavButton = { - display: 'inline-block', - padding: '6px 12px', - marginTop: '8px', - marginBottom: '8px', - fontSize: '14px', - fontWeight: 400, - lineHeight: '1.42857143', - textAlign: 'center', - whiteSpace: 'nowrap', - verticalAlign: 'middle', - touchAction: 'manipulation', - cursor: 'pointer', - userSelect: 'none', - backgroundImage: 'none', - border: '1px solid transparent', - borderRadius: '4px', - color: '#333', - backgroundColor: '#fff', - borderColor: '#ccc' + display: 'inline-block', + padding: '6px 12px', + marginTop: '8px', + marginBottom: '8px', + fontSize: '14px', + fontWeight: 400, + lineHeight: '1.42857143', + textAlign: 'center', + whiteSpace: 'nowrap', + verticalAlign: 'middle', + touchAction: 'manipulation', + cursor: 'pointer', + userSelect: 'none', + backgroundImage: 'none', + border: '1px solid transparent', + borderRadius: '4px', + color: '#333', + backgroundColor: '#fff', + borderColor: '#ccc', }; export const FormContainer = { - textAlign: 'center' + textAlign: 'center', }; export const FormSection = { - marginBottom: '20px', - backgroundColor: '#fff', - border: '1px solid #ddd', - borderRadius: '4px', - textAlign: 'left', - width: '400px', - display: 'inline-block' + marginBottom: '20px', + backgroundColor: '#fff', + border: '1px solid #ddd', + borderRadius: '4px', + textAlign: 'left', + width: '400px', + display: 'inline-block', }; export const ErrorSection = { - marginBottom: '20px', - color: '#fff', - backgroundColor: '#f0ad4e', - border: '1px solid #eea236', - borderRadius: '4px', - textAlign: 'left' + marginBottom: '20px', + color: '#fff', + backgroundColor: '#f0ad4e', + border: '1px solid #eea236', + borderRadius: '4px', + textAlign: 'left', }; export const SectionHeader = { - color: '#fff', - backgroundColor: '#337ab7', - borderColor: '#337ab7', - padding: '10px 15px', - borderBottom: '1px solid transparent', - borderTopLeftRadius: '3px', - borderTopRightRadius: '3px', - textAlign: 'center' + color: '#fff', + backgroundColor: '#337ab7', + borderColor: '#337ab7', + padding: '10px 15px', + borderBottom: '1px solid transparent', + borderTopLeftRadius: '3px', + borderTopRightRadius: '3px', + textAlign: 'center', }; export const SectionFooter = { - color: '#333', - backgroundColor: '#f5f5f5', - padding: '10px 15px', - borderTop: '1px solid #ddd', - borderTopLeftRadius: '3px', - borderTopRightRadius: '3px' + color: '#333', + backgroundColor: '#f5f5f5', + padding: '10px 15px', + borderTop: '1px solid #ddd', + borderTopLeftRadius: '3px', + borderTopRightRadius: '3px', }; export const SectionBody = { - padding: '15px' + padding: '15px', }; export const FormRow = { - marginBottom: '15px' + marginBottom: '15px', }; export const ActionRow = { - marginBottom: '15px' + marginBottom: '15px', }; export const Input = { - display: 'block', - width: '100%', - height: '34px', - padding: '6px 12px', - fontSize: '14px', - lineHeight: '1.42857143', - color: '#555', - backgroundColor: '#fff', - backgroundImage: 'none', - border: '1px solid #ccc', - borderRadius: '4px', - boxShadow: 'inset 0 1px 1px rgba(0,0,0,.075)', - boxSizing: 'border-box', - transition: 'border-color ease-in-out .15s,box-shadow ease-in-out .15s' + display: 'block', + width: '100%', + height: '34px', + padding: '6px 12px', + fontSize: '14px', + lineHeight: '1.42857143', + color: '#555', + backgroundColor: '#fff', + backgroundImage: 'none', + border: '1px solid #ccc', + borderRadius: '4px', + boxShadow: 'inset 0 1px 1px rgba(0,0,0,.075)', + boxSizing: 'border-box', + transition: 'border-color ease-in-out .15s,box-shadow ease-in-out .15s', }; export const Button = { - display: 'inline-block', - padding: '6px 12px', - marginBottom: '0', - fontSize: '14px', - fontWeight: 400, - lineHeight: '1.42857143', - textAlign: 'center', - whiteSpace: 'nowrap', - verticalAlign: 'middle', - touchAction: 'manipulation', - cursor: 'pointer', - userSelect: 'none', - backgroundImage: 'none', - border: '1px solid transparent', - borderRadius: '4px', - color: '#333', - backgroundColor: '#fff', - borderColor: '#ccc' + display: 'inline-block', + padding: '6px 12px', + marginBottom: '0', + fontSize: '14px', + fontWeight: 400, + lineHeight: '1.42857143', + textAlign: 'center', + whiteSpace: 'nowrap', + verticalAlign: 'middle', + touchAction: 'manipulation', + cursor: 'pointer', + userSelect: 'none', + backgroundImage: 'none', + border: '1px solid transparent', + borderRadius: '4px', + color: '#333', + backgroundColor: '#fff', + borderColor: '#ccc', }; export const SignInButton = { - position: 'relative', - padding: '6px 12px 6px 44px', - fontSize: '14px', - textAlign: 'left', - whiteSpace: 'nowrap', - overflow: 'hidden', - textOverflow: 'ellipsis', - display: 'block', - width: '100%', - marginTop: '2px', - '#google_signin_btn': { - color: '#fff', - backgroundColor: '#dd4b39', - borderColor: 'rgba(0,0,0,0.2)', - }, - '#facebook_signin_btn': { - color: '#fff', - backgroundColor: '#3b5998', - borderColor: 'rgba(0,0,0,0.2)', - } + position: 'relative', + padding: '6px 12px 6px 44px', + fontSize: '14px', + textAlign: 'left', + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', + display: 'block', + width: '100%', + marginTop: '2px', + '#google_signin_btn': { + color: '#fff', + backgroundColor: '#dd4b39', + borderColor: 'rgba(0,0,0,0.2)', + }, + '#facebook_signin_btn': { + color: '#fff', + backgroundColor: '#3b5998', + borderColor: 'rgba(0,0,0,0.2)', + }, }; export const Space = { - display: 'inline-block', - width: '20px' + display: 'inline-block', + width: '20px', }; export const A = { - color: '#007bff', - cursor: 'pointer' + color: '#007bff', + cursor: 'pointer', }; export const Pre = { - overflow: 'auto', - fontFamily: `Menlo, + overflow: 'auto', + fontFamily: `Menlo, Monaco, Consolas, "Courier New", monospace`, - display: 'block', - padding: '9.5px', - margin: '0 0 10px', - fontSize: '13px', - lineHeight: '1.42857143', - color: '#333', - wordBreak: 'break-all', - wordWrap: 'break-word', - backgroundColor: '#f5f5f5', - border: '1px solid #ccc', - borderRadius: '4px' + display: 'block', + padding: '9.5px', + margin: '0 0 10px', + fontSize: '13px', + lineHeight: '1.42857143', + color: '#333', + wordBreak: 'break-all', + wordWrap: 'break-word', + backgroundColor: '#f5f5f5', + border: '1px solid #ccc', + borderRadius: '4px', }; export const Col1 = { - display: 'inline-block', - width: '8.33333333%' + display: 'inline-block', + width: '8.33333333%', }; export const Col2 = { - display: 'inline-block', - width: '16.66666667%' + display: 'inline-block', + width: '16.66666667%', }; export const Col3 = { - display: 'inline-block', - width: '25%' + display: 'inline-block', + width: '25%', }; export const Col4 = { - display: 'inline-block', - width: '33.33333333%' + display: 'inline-block', + width: '33.33333333%', }; export const Col5 = { - display: 'inline-block', - width: '41.66666667%' + display: 'inline-block', + width: '41.66666667%', }; export const Col6 = { - display: 'inline-block', - width: '50%' + display: 'inline-block', + width: '50%', }; export const Col7 = { - display: 'inline-block', - width: '58.33333333%' + display: 'inline-block', + width: '58.33333333%', }; export const Col8 = { - display: 'inline-block', - width: '66.66666667%' + display: 'inline-block', + width: '66.66666667%', }; export const Col9 = { - display: 'inline-block', - width: '75%' + display: 'inline-block', + width: '75%', }; export const Col10 = { - display: 'inline-block', - width: '83.33333333%' + display: 'inline-block', + width: '83.33333333%', }; export const Col11 = { - display: 'inline-block', - width: '91.66666667%' + display: 'inline-block', + width: '91.66666667%', }; export const Col12 = { - display: 'inline-block', - width: '100%' + display: 'inline-block', + width: '100%', }; export const Hidden = { - display: 'none' + display: 'none', }; const Bootstrap = { - container: Container, - - navBar: NavBar, - nav: Nav, - navRight: NavRight, - navItem: NavItem, - navButton: NavButton, - - formContainer: FormContainer, - formSection: FormSection, - errorSection: ErrorSection, - sectionHeader: SectionHeader, - sectionBody: SectionBody, - sectionFooter: SectionFooter, - - formRow: FormRow, - actionRow: ActionRow, - - space: Space, - - signInButton: SignInButton, - - input: Input, - button: Button, - a: A, - pre: Pre, - - col1: Col1, - col2: Col2, - col3: Col3, - col4: Col4, - col5: Col5, - col6: Col6, - col7: Col7, - col8: Col8, - col9: Col9, - col10: Col10, - col11: Col11, - col12: Col12, - - hidden: Hidden, + container: Container, + + navBar: NavBar, + nav: Nav, + navRight: NavRight, + navItem: NavItem, + navButton: NavButton, + + formContainer: FormContainer, + formSection: FormSection, + errorSection: ErrorSection, + sectionHeader: SectionHeader, + sectionBody: SectionBody, + sectionFooter: SectionFooter, + + formRow: FormRow, + actionRow: ActionRow, + + space: Space, + + signInButton: SignInButton, + + input: Input, + button: Button, + a: A, + pre: Pre, + + col1: Col1, + col2: Col2, + col3: Col3, + col4: Col4, + col5: Col5, + col6: Col6, + col7: Col7, + col8: Col8, + col9: Col9, + col10: Col10, + col11: Col11, + col12: Col12, + + hidden: Hidden, }; export default Bootstrap; diff --git a/packages/aws-amplify-react/src/AmplifyUI.jsx b/packages/aws-amplify-react/src/AmplifyUI.jsx index aae2a579de4..481b14ad2e5 100644 --- a/packages/aws-amplify-react/src/AmplifyUI.jsx +++ b/packages/aws-amplify-react/src/AmplifyUI.jsx @@ -17,389 +17,373 @@ import { JS } from '@aws-amplify/core'; import AmplifyTheme from './AmplifyTheme'; -export const Container = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.container); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const FormContainer = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.formContainer); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const FormSection = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.formSection); - return ( - - {beforeAfter( -
- {props.children} -
- )} -
- ); -}; - -export const ErrorSection = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.errorSection); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- - {props.children} - -
- ); -}; - -export const ErrorSectionContent = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.errorSectionContent); - return beforeAfter( - - {props.children} - - ); -}; - -export const SectionHeader = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.sectionHeader); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- - {props.children} - -
- ); -}; - -export const SectionHeaderContent = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.sectionHeaderContent); - return beforeAfter( - - {props.children} - - ); -}; - -export const SectionFooter = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.sectionFooter); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- - {props.children} - -
- ); -}; - -export const SectionFooterContent = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.sectionFooterContent); - return beforeAfter( - - {props.children} - - ); -}; - -export const SectionBody = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.sectionBody); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const ActionRow = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.actionRow); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const FormRow = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.formRow); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const InputRow = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.input); - const p = JS.objectLessAttributes(props, 'theme'); - return ( - - {beforeAfter( - - )} - - ); -}; - -export const RadioRow = (props) => { - const id = props.id || '_' + props.value; - const theme = props.theme || AmplifyTheme; - return ( - - - - - ); -}; - -export const Radio = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.radio); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - - ); -}; - -export const CheckboxRow = (props) => { - const id = props.id || '_' + props.name; - const theme = props.theme || AmplifyTheme; - return ( - - - - - ); -}; - -export const Checkbox = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.checkbox); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - - ); -}; - -export const MessageRow = (props) => { - const theme = props.theme || AmplifyTheme; - return ( - - {props.children} - - ); -}; - -export const MessageContent = (props) => { - const theme = props.theme || AmplifyTheme; - return beforeAfter( - - {props.children} - - ); -}; - -export const ButtonRow = (props) => { - const theme = props.theme || AmplifyTheme; - return beforeAfter( -
-
- ); -}; - -export const Button = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.button); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - - ); -}; - -export const ButtonContent = (props) => { - const theme = props.theme || AmplifyTheme; - return beforeAfter( - - {props.children} - - ); -}; - -export const SignInButton = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.signInButton); - const p = JS.objectLessAttributes(props, 'theme'); - - return beforeAfter( - - ); -}; - -export const Link = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.a); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
{props.children} - ); -}; - -export const Label = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.label); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - - ); -}; - -export const Space = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.space); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - {props.children} - ); -}; - -export const NavBar = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.navBar); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const Nav = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.nav); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const NavRight = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.navRight); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const NavItem = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.navItem); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( -
- {props.children} -
- ); -}; - -export const NavButton = (props) => { - const theme = props.theme || AmplifyTheme; - const style = propStyle(props, theme.navButton); - const p = JS.objectLessAttributes(props, 'theme'); - return beforeAfter( - - ); -}; - -export const beforeAfter = (el) => { - const style = el.props.style || {}; - const { before, after } = style; - if (!before && !after) { return el; } - - return ( - - {before? {before.content} : null} - {el} - {after? {after.content} : null} - - ); +export const Container = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.container); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const FormContainer = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.formContainer); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const FormSection = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.formSection); + return ( + + {beforeAfter( +
+ {props.children} +
+ )} +
+ ); +}; + +export const ErrorSection = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.errorSection); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const ErrorSectionContent = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.errorSectionContent); + return beforeAfter( + + {props.children} + + ); +}; + +export const SectionHeader = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.sectionHeader); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ + {props.children} + +
+ ); +}; + +export const SectionHeaderContent = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.sectionHeaderContent); + return beforeAfter( + + {props.children} + + ); +}; + +export const SectionFooter = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.sectionFooter); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const SectionFooterContent = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.sectionFooterContent); + return beforeAfter( + + {props.children} + + ); +}; + +export const SectionBody = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.sectionBody); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const ActionRow = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.actionRow); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const FormRow = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.formRow); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const InputRow = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.input); + const p = JS.objectLessAttributes(props, 'theme'); + return ( + + {beforeAfter()} + + ); +}; + +export const RadioRow = props => { + const id = props.id || '_' + props.value; + const theme = props.theme || AmplifyTheme; + return ( + + + + + ); +}; + +export const Radio = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.radio); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + ); +}; + +export const CheckboxRow = props => { + const id = props.id || '_' + props.name; + const theme = props.theme || AmplifyTheme; + return ( + + + + + ); +}; + +export const Checkbox = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.checkbox); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + ); +}; + +export const MessageRow = props => { + const theme = props.theme || AmplifyTheme; + return ( + + {props.children} + + ); +}; + +export const MessageContent = props => { + const theme = props.theme || AmplifyTheme; + return beforeAfter( + + {props.children} + + ); +}; + +export const ButtonRow = props => { + const theme = props.theme || AmplifyTheme; + return beforeAfter( +
+
+ ); +}; + +export const Button = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.button); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + ); +}; + +export const ButtonContent = props => { + const theme = props.theme || AmplifyTheme; + return beforeAfter( + + {props.children} + + ); +}; + +export const SignInButton = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.signInButton); + const p = JS.objectLessAttributes(props, 'theme'); + + return beforeAfter( + + ); +}; + +export const Link = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.a); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + {props.children} + + ); +}; + +export const Label = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.label); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + ); +}; + +export const Space = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.space); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + {props.children} + + ); +}; + +export const NavBar = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.navBar); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const Nav = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.nav); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const NavRight = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.navRight); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const NavItem = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.navItem); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( +
+ {props.children} +
+ ); +}; + +export const NavButton = props => { + const theme = props.theme || AmplifyTheme; + const style = propStyle(props, theme.navButton); + const p = JS.objectLessAttributes(props, 'theme'); + return beforeAfter( + + ); +}; + +export const beforeAfter = el => { + const style = el.props.style || {}; + const { before, after } = style; + if (!before && !after) { + return el; + } + + return ( + + {before ? {before.content} : null} + {el} + {after ? {after.content} : null} + + ); }; export const propStyle = (props, themeStyle) => { - const { id, style } = props; - const styl = Object.assign({}, style, themeStyle); - if (!id) { return styl; } + const { id, style } = props; + const styl = Object.assign({}, style, themeStyle); + if (!id) { + return styl; + } - const selector = '#' + id; - Object.assign(styl, styl[selector]); - return styl; + const selector = '#' + id; + Object.assign(styl, styl[selector]); + return styl; }; -export const transparent1X1 = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='; +export const transparent1X1 = + 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='; -export const white1X1 = 'data:image/gif;base64,R0lGODlhAQABAIAAAP7//wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=='; +export const white1X1 = + 'data:image/gif;base64,R0lGODlhAQABAIAAAP7//wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=='; diff --git a/packages/aws-amplify-react/src/Analytics/trackLifecycle.jsx b/packages/aws-amplify-react/src/Analytics/trackLifecycle.jsx index 067bdb8ab4f..aa8708e7c4e 100644 --- a/packages/aws-amplify-react/src/Analytics/trackLifecycle.jsx +++ b/packages/aws-amplify-react/src/Analytics/trackLifecycle.jsx @@ -16,82 +16,87 @@ import { Component } from 'react'; import Analytics from '@aws-amplify/analytics'; const Default_Track_Events = [ - 'componentDidMount', - 'componentDidUpdate', - 'compomentWillUnmount', - 'compomentDidCatch', - 'render' + 'componentDidMount', + 'componentDidUpdate', + 'compomentWillUnmount', + 'compomentDidCatch', + 'render', ]; -export function trackLifecycle(Comp, trackerName, events=Default_Track_Events) { - return class WithTrackLifecycle extends Component { - constructor(props) { - super(props); - this.trackerName = trackerName; - this.trackEvents = events; - - this.track('constructor'); - } - - track(event) { - const filtered = this.trackEvents.filter(item => item === event); - if (filtered.length > 0) { - if (Analytics && typeof Analytics.record === 'function') { - Analytics.record({ - name: this.trackerName, - attributes: { event } - }); - } else { - throw new Error('No Analytics module found, please ensure @aws-amplify/analytics is imported'); - } - - } - } - - componentWillMount() { - this.track('componentWillMount'); - } - - componentDidMount() { - this.track('componentDidMount'); - } - - componentWillUnmount() { - this.track('componentWillUnmount'); - } - - componentDidCatch() { - this.track('componentDidCatch'); - } - - componentWillReceiveProps() { - this.track('componentWillReceiveProps'); - } - - shouldComponentUpdate() { - this.track('shouldComponentUpdate'); - return true; - } - - componentWillUpdate() { - this.track('componentWillUpdate'); - } - - componentDidUpdate() { - this.track('componentDidUpdate'); - } - - setState() { - this.track('setState'); - } - - forceUpdate() { - this.track('forceUpdate'); - } - - render() { - this.track('render'); - return ; - } - }; +export function trackLifecycle( + Comp, + trackerName, + events = Default_Track_Events +) { + return class WithTrackLifecycle extends Component { + constructor(props) { + super(props); + this.trackerName = trackerName; + this.trackEvents = events; + + this.track('constructor'); + } + + track(event) { + const filtered = this.trackEvents.filter(item => item === event); + if (filtered.length > 0) { + if (Analytics && typeof Analytics.record === 'function') { + Analytics.record({ + name: this.trackerName, + attributes: { event }, + }); + } else { + throw new Error( + 'No Analytics module found, please ensure @aws-amplify/analytics is imported' + ); + } + } + } + + componentWillMount() { + this.track('componentWillMount'); + } + + componentDidMount() { + this.track('componentDidMount'); + } + + componentWillUnmount() { + this.track('componentWillUnmount'); + } + + componentDidCatch() { + this.track('componentDidCatch'); + } + + componentWillReceiveProps() { + this.track('componentWillReceiveProps'); + } + + shouldComponentUpdate() { + this.track('shouldComponentUpdate'); + return true; + } + + componentWillUpdate() { + this.track('componentWillUpdate'); + } + + componentDidUpdate() { + this.track('componentDidUpdate'); + } + + setState() { + this.track('setState'); + } + + forceUpdate() { + this.track('forceUpdate'); + } + + render() { + this.track('render'); + return ; + } + }; } diff --git a/packages/aws-amplify-react/src/Analytics/trackUpdate.jsx b/packages/aws-amplify-react/src/Analytics/trackUpdate.jsx index f278e40c8a9..66a7528174a 100644 --- a/packages/aws-amplify-react/src/Analytics/trackUpdate.jsx +++ b/packages/aws-amplify-react/src/Analytics/trackUpdate.jsx @@ -16,26 +16,28 @@ import { Component } from 'react'; import Analytics from '@aws-amplify/analytics'; export function trackUpdate(Comp, trackerName) { - return class extends Component { - constructor(props) { - super(props); - this.trackerName = trackerName; - } + return class extends Component { + constructor(props) { + super(props); + this.trackerName = trackerName; + } - componentDidUpdate(prevProps, prevState) { - const attributes = Object.assign({}, this.props, this.state); - if (Analytics && typeof Analytics.record === 'function') { - Analytics.record({ - name: this.trackerName, - attributes - }); - } else { - throw new Error('No Analytics module found, please ensure @aws-amplify/analytics is imported'); - } - } + componentDidUpdate(prevProps, prevState) { + const attributes = Object.assign({}, this.props, this.state); + if (Analytics && typeof Analytics.record === 'function') { + Analytics.record({ + name: this.trackerName, + attributes, + }); + } else { + throw new Error( + 'No Analytics module found, please ensure @aws-amplify/analytics is imported' + ); + } + } - render() { - return ; - } - }; + render() { + return ; + } + }; } diff --git a/packages/aws-amplify-react/src/Auth/AuthPiece.jsx b/packages/aws-amplify-react/src/Auth/AuthPiece.jsx index d038b55f5ba..c196d874934 100644 --- a/packages/aws-amplify-react/src/Auth/AuthPiece.jsx +++ b/packages/aws-amplify-react/src/Auth/AuthPiece.jsx @@ -16,177 +16,190 @@ import { ConsoleLogger as Logger, I18n } from '@aws-amplify/core'; import Auth from '@aws-amplify/auth'; import AmplifyTheme from '../Amplify-UI/Amplify-UI-Theme'; import countryDialCodes from './common/country-dial-codes.js'; -import { - FormField, - Input, - InputLabel, - SelectInput - } from '../Amplify-UI/Amplify-UI-Components-React'; +import { + FormField, + Input, + InputLabel, + SelectInput, +} from '../Amplify-UI/Amplify-UI-Components-React'; import { UsernameAttributes } from './common/types'; import { PhoneField } from './PhoneField'; import { auth } from '../Amplify-UI/data-test-attributes'; const labelMap = { - [UsernameAttributes.EMAIL]: 'Email', - [UsernameAttributes.PHONE_NUMBER]: 'Phone Number', - [UsernameAttributes.USERNAME]: 'Username' + [UsernameAttributes.EMAIL]: 'Email', + [UsernameAttributes.PHONE_NUMBER]: 'Phone Number', + [UsernameAttributes.USERNAME]: 'Username', }; export default class AuthPiece extends React.Component { - constructor(props) { - super(props); - - this.inputs = {}; - - this._isHidden = true; - this._validAuthStates = []; - this.phone_number = ''; - this.changeState = this.changeState.bind(this); - this.error = this.error.bind(this); - this.handleInputChange = this.handleInputChange.bind(this); - this.renderUsernameField = this.renderUsernameField.bind(this); - this.getUsernameFromInput = this.getUsernameFromInput.bind(this); - this.onPhoneNumberChanged = this.onPhoneNumberChanged.bind(this); - } - - componentDidMount() { - if (window && window.location && window.location.search) { - if (!this.props.authData || !this.props.authData.username) { - const searchParams = new URLSearchParams(window.location.search); - const username = searchParams ? searchParams.get('username') : undefined; - this.setState({ username }); - } - } - } - - getUsernameFromInput() { - const { usernameAttributes = 'username' } = this.props; - switch(usernameAttributes) { - case UsernameAttributes.EMAIL: - return this.inputs.email; - case UsernameAttributes.PHONE_NUMBER: - return this.phone_number; - default: - return this.inputs.username || this.state.username; - } - } - - onPhoneNumberChanged(phone_number) { - this.phone_number = phone_number; - } - - renderUsernameField(theme) { - const { usernameAttributes = [] } = this.props; - if (usernameAttributes === UsernameAttributes.EMAIL) { - return ( - - {I18n.get('Email')} * - - - ); - } else if (usernameAttributes === UsernameAttributes.PHONE_NUMBER) { - return ( - - ); - } else { - return ( - - {I18n.get(this.getUsernameLabel())} * - - - ); - } - } - - getUsernameLabel() { - const { usernameAttributes = UsernameAttributes.USERNAME } = this.props; - return labelMap[usernameAttributes] || usernameAttributes; - } - - // extract username from authData - usernameFromAuthData() { - const { authData } = this.props; - if (!authData) { return ''; } - - let username = ''; - if (typeof authData === 'object') { // user object - username = authData.user? authData.user.username : authData.username; - } else { - username = authData; // username string - } - - return username; - } - - errorMessage(err) { - if (typeof err === 'string') { return err; } - return err.message? err.message : JSON.stringify(err); - } - - triggerAuthEvent(event) { - const state = this.props.authState; - if (this.props.onAuthEvent) { this.props.onAuthEvent(state, event); } - } - - changeState(state, data) { - if (this.props.onStateChange) { this.props.onStateChange(state, data); } - - this.triggerAuthEvent({ - type: 'stateChange', - data: state - }); - } - - error(err) { - this.triggerAuthEvent({ - type: 'error', - data: this.errorMessage(err) - }); - } - - handleInputChange(evt) { - this.inputs = this.inputs || {}; - const { name, value, type, checked } = evt.target; - const check_type = ['radio', 'checkbox'].includes(type); - this.inputs[name] = check_type? checked : value; - this.inputs['checkedValue'] = check_type? value: null; - } - - render() { - if (!this._validAuthStates.includes(this.props.authState)) { - this._isHidden = true; - this.inputs = {}; - return null; - } - - if (this._isHidden) { - this.inputs = {}; - const { track } = this.props; - if (track) track(); - } - this._isHidden = false; - - return this.showComponent(this.props.theme || AmplifyTheme); - } - - showComponent(theme) { - throw 'You must implement showComponent(theme) and don\'t forget to set this._validAuthStates.'; - } + constructor(props) { + super(props); + + this.inputs = {}; + + this._isHidden = true; + this._validAuthStates = []; + this.phone_number = ''; + this.changeState = this.changeState.bind(this); + this.error = this.error.bind(this); + this.handleInputChange = this.handleInputChange.bind(this); + this.renderUsernameField = this.renderUsernameField.bind(this); + this.getUsernameFromInput = this.getUsernameFromInput.bind(this); + this.onPhoneNumberChanged = this.onPhoneNumberChanged.bind(this); + } + + componentDidMount() { + if (window && window.location && window.location.search) { + if (!this.props.authData || !this.props.authData.username) { + const searchParams = new URLSearchParams(window.location.search); + const username = searchParams + ? searchParams.get('username') + : undefined; + this.setState({ username }); + } + } + } + + getUsernameFromInput() { + const { usernameAttributes = 'username' } = this.props; + switch (usernameAttributes) { + case UsernameAttributes.EMAIL: + return this.inputs.email; + case UsernameAttributes.PHONE_NUMBER: + return this.phone_number; + default: + return this.inputs.username || this.state.username; + } + } + + onPhoneNumberChanged(phone_number) { + this.phone_number = phone_number; + } + + renderUsernameField(theme) { + const { usernameAttributes = [] } = this.props; + if (usernameAttributes === UsernameAttributes.EMAIL) { + return ( + + {I18n.get('Email')} * + + + ); + } else if (usernameAttributes === UsernameAttributes.PHONE_NUMBER) { + return ( + + ); + } else { + return ( + + + {I18n.get(this.getUsernameLabel())} * + + + + ); + } + } + + getUsernameLabel() { + const { usernameAttributes = UsernameAttributes.USERNAME } = this.props; + return labelMap[usernameAttributes] || usernameAttributes; + } + + // extract username from authData + usernameFromAuthData() { + const { authData } = this.props; + if (!authData) { + return ''; + } + + let username = ''; + if (typeof authData === 'object') { + // user object + username = authData.user ? authData.user.username : authData.username; + } else { + username = authData; // username string + } + + return username; + } + + errorMessage(err) { + if (typeof err === 'string') { + return err; + } + return err.message ? err.message : JSON.stringify(err); + } + + triggerAuthEvent(event) { + const state = this.props.authState; + if (this.props.onAuthEvent) { + this.props.onAuthEvent(state, event); + } + } + + changeState(state, data) { + if (this.props.onStateChange) { + this.props.onStateChange(state, data); + } + + this.triggerAuthEvent({ + type: 'stateChange', + data: state, + }); + } + + error(err) { + this.triggerAuthEvent({ + type: 'error', + data: this.errorMessage(err), + }); + } + + handleInputChange(evt) { + this.inputs = this.inputs || {}; + const { name, value, type, checked } = evt.target; + const check_type = ['radio', 'checkbox'].includes(type); + this.inputs[name] = check_type ? checked : value; + this.inputs['checkedValue'] = check_type ? value : null; + } + + render() { + if (!this._validAuthStates.includes(this.props.authState)) { + this._isHidden = true; + this.inputs = {}; + return null; + } + + if (this._isHidden) { + this.inputs = {}; + const { track } = this.props; + if (track) track(); + } + this._isHidden = false; + + return this.showComponent(this.props.theme || AmplifyTheme); + } + + showComponent(theme) { + throw "You must implement showComponent(theme) and don't forget to set this._validAuthStates."; + } } diff --git a/packages/aws-amplify-react/src/Auth/AuthStateWrapper.jsx b/packages/aws-amplify-react/src/Auth/AuthStateWrapper.jsx index 6b8ba0fb2bd..92336002008 100644 --- a/packages/aws-amplify-react/src/Auth/AuthStateWrapper.jsx +++ b/packages/aws-amplify-react/src/Auth/AuthStateWrapper.jsx @@ -8,80 +8,87 @@ import AmplifyTheme from '../Amplify-UI/Amplify-UI-Theme'; const logger = new Logger('AuthStateWrapper'); export default class AuthStateWrapper extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.handleStateChange = this.handleStateChange.bind(this); - this.handleAuthEvent = this.handleAuthEvent.bind(this); - this.checkUser = this.checkUser.bind(this); + this.handleStateChange = this.handleStateChange.bind(this); + this.handleAuthEvent = this.handleAuthEvent.bind(this); + this.checkUser = this.checkUser.bind(this); - this.state = { authState: props.authState || 'signIn' }; - } + this.state = { authState: props.authState || 'signIn' }; + } - componentWillMount() { - const config = this.props.amplifyConfig; - if (config) { - Amplify.configure(config); - } - } + componentWillMount() { + const config = this.props.amplifyConfig; + if (config) { + Amplify.configure(config); + } + } - componentDidMount() { - this.checkUser(); - } + componentDidMount() { + this.checkUser(); + } - handleStateChange(state, data) { - logger.debug('authStateWrapper state change ' + state, data); - if (state === this.state.authState) { return; } + handleStateChange(state, data) { + logger.debug('authStateWrapper state change ' + state, data); + if (state === this.state.authState) { + return; + } - if (state === 'signedOut') { state = 'signIn'; } - this.setState({ authState: state, authData: data, error: null }); - if (this.props.onStateChange) { this.props.onStateChange(state, data); } - } + if (state === 'signedOut') { + state = 'signIn'; + } + this.setState({ authState: state, authData: data, error: null }); + if (this.props.onStateChange) { + this.props.onStateChange(state, data); + } + } - handleAuthEvent(state, event) { - if (event.type === 'error') { - this.setState({ error: event.data }); - } - } + handleAuthEvent(state, event) { + if (event.type === 'error') { + this.setState({ error: event.data }); + } + } - checkUser() { - if (!Auth || typeof Auth.currentUser !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - return Auth.currentUser() - .then(user => { - const state = user? 'signedIn' : 'signIn'; - this.handleStateChange(state, user); - }) - .catch(err => logger.error(err)); - } + checkUser() { + if (!Auth || typeof Auth.currentUser !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + return Auth.currentUser() + .then(user => { + const state = user ? 'signedIn' : 'signIn'; + this.handleStateChange(state, user); + }) + .catch(err => logger.error(err)); + } - render() { - const { authState, authData } = this.state; - const theme = this.props.theme || AmplifyTheme; - const render_children = React.Children.map(this.props.children, (child) => { - if (!child) { return null; } - return React.cloneElement(child, { - authState, - authData, - theme, - onStateChange: this.handleStateChange, - onAuthEvent: this.handleAuthEvent - }); - }); + render() { + const { authState, authData } = this.state; + const theme = this.props.theme || AmplifyTheme; + const render_children = React.Children.map(this.props.children, child => { + if (!child) { + return null; + } + return React.cloneElement(child, { + authState, + authData, + theme, + onStateChange: this.handleStateChange, + onAuthEvent: this.handleAuthEvent, + }); + }); - return ( -
- {render_children} - {this.state.error && -
- {this.state.error} -
- } -
- ); - } + return ( +
+ {render_children} + {this.state.error && ( +
+ {this.state.error} +
+ )} +
+ ); + } } diff --git a/packages/aws-amplify-react/src/Auth/Authenticator.jsx b/packages/aws-amplify-react/src/Auth/Authenticator.jsx index f01f4c8a066..98dcb02dd27 100644 --- a/packages/aws-amplify-react/src/Auth/Authenticator.jsx +++ b/packages/aws-amplify-react/src/Auth/Authenticator.jsx @@ -39,208 +39,253 @@ const AUTHENTICATOR_AUTHSTATE = 'amplify-authenticator-authState'; export const EmptyContainer = ({ children }) => <>{children}; export default class Authenticator extends Component { - constructor(props) { - super(props); - - this.handleStateChange = this.handleStateChange.bind(this); - this.handleAuthEvent = this.handleAuthEvent.bind(this); - this.onHubCapsule = this.onHubCapsule.bind(this); - - this._initialAuthState = this.props.authState || 'signIn'; - this.state = { authState: 'loading' }; - Hub.listen('auth', this.onHubCapsule); - } - - componentDidMount() { - const config = this.props.amplifyConfig; - if (config) { - Amplify.configure(config); - } - this._isMounted = true; - // the workaround for Cognito Hosted UI - // don't check the user immediately if redirected back from Hosted UI - // instead waiting for the hub event sent from Auth module - // the item in the localStorage is a mark to indicate whether - // the app is redirected back from Hosted UI or not - const byHostedUI = localStorage.getItem(Constants.SIGNING_IN_WITH_HOSTEDUI_KEY); - localStorage.removeItem(Constants.SIGNING_IN_WITH_HOSTEDUI_KEY); - if (byHostedUI !== 'true') this.checkUser(); - } - - componentWillUnmount() { - this._isMounted = false; - } - checkUser() { - if (!Auth || typeof Auth.currentAuthenticatedUser !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - return Auth.currentAuthenticatedUser() - .then(user => { - if (!this._isMounted) { return; } - this.handleStateChange('signedIn', user); - }) - .catch(err => { - if (!this._isMounted) { return; } - let cachedAuthState = null; - try { - cachedAuthState = localStorage.getItem(AUTHENTICATOR_AUTHSTATE); - } catch (e) { - logger.debug('Failed to get the auth state from local storage', e); - } - const promise = cachedAuthState === 'signedIn'? Auth.signOut() : Promise.resolve(); - promise.then(() => this.handleStateChange(this._initialAuthState)) - .catch((e) => { - logger.debug('Failed to sign out', e); - }); - }); - } - - onHubCapsule(capsule) { - const { channel, payload, source } = capsule; - if (channel === 'auth') { - switch (payload.event) { - case 'cognitoHostedUI': - this.handleStateChange('signedIn', payload.data); - break; - case 'cognitoHostedUI_failure': - this.handleStateChange('signIn', null); - break; - case 'parsingUrl_failure': - this.handleStateChange('signIn', null); - break; - case 'signOut': - this.handleStateChange('signIn', null); - break; - case 'customGreetingSignOut': - this.handleStateChange('signIn', null); - break; - case 'parsingCallbackUrl': - localStorage.setItem(Constants.SIGNING_IN_WITH_HOSTEDUI_KEY, 'true'); - break; - default: - break; - } - } - } - - handleStateChange(state, data) { - logger.debug('authenticator state change ' + state, data); - if (state === this.state.authState) { return; } - - if (state === 'signedOut') { state = 'signIn'; } - try { - localStorage.setItem(AUTHENTICATOR_AUTHSTATE, state); - } catch (e) { - logger.debug('Failed to set the auth state into local storage', e); - } - - if (this._isMounted) { - this.setState({ authState: state, authData: data, error: null, showToast: false }); - } - if (this.props.onStateChange) { this.props.onStateChange(state, data); } - } - - handleAuthEvent(state, event, showToast = true) { - if (event.type === 'error') { - const map = this.props.errorMessage || AmplifyMessageMap; - const message = (typeof map === 'string')? map : map(event.data); - this.setState({ error: message, showToast }); - - } - } - - render() { - const { authState, authData } = this.state; - const theme = this.props.theme || AmplifyTheme; - const messageMap = this.props.errorMessage || AmplifyMessageMap; - // If container prop is undefined, default to AWS Amplify UI Container - // otherwise if truthy, use the supplied render prop - // otherwise if falsey, use EmptyContainer - const Wrapper = this.props.container === undefined ? Container : this.props.container || EmptyContainer; - - let { hideDefault, hide = [], federated, signUpConfig, usernameAttributes } = this.props; - if (hideDefault) { - hide = hide.concat([ - Greetings, - SignIn, - ConfirmSignIn, - RequireNewPassword, - SignUp, - ConfirmSignUp, - VerifyContact, - ForgotPassword, - TOTPSetup, - Loading - ]); - } - - let props_children = []; - if (typeof this.props.children === 'object') { - if (Array.isArray(this.props.children)){ - props_children = this.props.children; - } else { - props_children.push(this.props.children); - } - } - - const default_children = [ - , - , - , - , - , - , - , - , - , - - ]; - - const props_children_override = React.Children.map(props_children, child => child.props.override); - hide = hide.filter((component) => !props_children.find(child => child.type === component)); - - const render_props_children = React.Children.map(props_children, (child, index) => { - return React.cloneElement(child, { - key: 'aws-amplify-authenticator-props-children-' + index, - theme, - messageMap, - authState, - authData, - onStateChange: this.handleStateChange, - onAuthEvent: this.handleAuthEvent, - hide, - override: props_children_override, - usernameAttributes - }); - }); - - const render_default_children = hideDefault ? [] : React.Children.map(default_children, (child, index) => { - return React.cloneElement(child, { - key: 'aws-amplify-authenticator-default-children-' + index, - theme, - messageMap, - authState, - authData, - onStateChange: this.handleStateChange, - onAuthEvent: this.handleAuthEvent, - hide, - override: props_children_override, - usernameAttributes - }); - }); - - const render_children = render_default_children.concat(render_props_children); - const error = this.state.error; - - return ( - - {this.state.showToast && - this.setState({showToast: false})} data-test={auth.signIn.signInError}> - { I18n.get(error) } - - } - {render_children} - - ); - } + constructor(props) { + super(props); + + this.handleStateChange = this.handleStateChange.bind(this); + this.handleAuthEvent = this.handleAuthEvent.bind(this); + this.onHubCapsule = this.onHubCapsule.bind(this); + + this._initialAuthState = this.props.authState || 'signIn'; + this.state = { authState: 'loading' }; + Hub.listen('auth', this.onHubCapsule); + } + + componentDidMount() { + const config = this.props.amplifyConfig; + if (config) { + Amplify.configure(config); + } + this._isMounted = true; + // the workaround for Cognito Hosted UI + // don't check the user immediately if redirected back from Hosted UI + // instead waiting for the hub event sent from Auth module + // the item in the localStorage is a mark to indicate whether + // the app is redirected back from Hosted UI or not + const byHostedUI = localStorage.getItem( + Constants.SIGNING_IN_WITH_HOSTEDUI_KEY + ); + localStorage.removeItem(Constants.SIGNING_IN_WITH_HOSTEDUI_KEY); + if (byHostedUI !== 'true') this.checkUser(); + } + + componentWillUnmount() { + this._isMounted = false; + } + checkUser() { + if (!Auth || typeof Auth.currentAuthenticatedUser !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + return Auth.currentAuthenticatedUser() + .then(user => { + if (!this._isMounted) { + return; + } + this.handleStateChange('signedIn', user); + }) + .catch(err => { + if (!this._isMounted) { + return; + } + let cachedAuthState = null; + try { + cachedAuthState = localStorage.getItem(AUTHENTICATOR_AUTHSTATE); + } catch (e) { + logger.debug('Failed to get the auth state from local storage', e); + } + const promise = + cachedAuthState === 'signedIn' ? Auth.signOut() : Promise.resolve(); + promise + .then(() => this.handleStateChange(this._initialAuthState)) + .catch(e => { + logger.debug('Failed to sign out', e); + }); + }); + } + + onHubCapsule(capsule) { + const { channel, payload, source } = capsule; + if (channel === 'auth') { + switch (payload.event) { + case 'cognitoHostedUI': + this.handleStateChange('signedIn', payload.data); + break; + case 'cognitoHostedUI_failure': + this.handleStateChange('signIn', null); + break; + case 'parsingUrl_failure': + this.handleStateChange('signIn', null); + break; + case 'signOut': + this.handleStateChange('signIn', null); + break; + case 'customGreetingSignOut': + this.handleStateChange('signIn', null); + break; + case 'parsingCallbackUrl': + localStorage.setItem(Constants.SIGNING_IN_WITH_HOSTEDUI_KEY, 'true'); + break; + default: + break; + } + } + } + + handleStateChange(state, data) { + logger.debug('authenticator state change ' + state, data); + if (state === this.state.authState) { + return; + } + + if (state === 'signedOut') { + state = 'signIn'; + } + try { + localStorage.setItem(AUTHENTICATOR_AUTHSTATE, state); + } catch (e) { + logger.debug('Failed to set the auth state into local storage', e); + } + + if (this._isMounted) { + this.setState({ + authState: state, + authData: data, + error: null, + showToast: false, + }); + } + if (this.props.onStateChange) { + this.props.onStateChange(state, data); + } + } + + handleAuthEvent(state, event, showToast = true) { + if (event.type === 'error') { + const map = this.props.errorMessage || AmplifyMessageMap; + const message = typeof map === 'string' ? map : map(event.data); + this.setState({ error: message, showToast }); + } + } + + render() { + const { authState, authData } = this.state; + const theme = this.props.theme || AmplifyTheme; + const messageMap = this.props.errorMessage || AmplifyMessageMap; + // If container prop is undefined, default to AWS Amplify UI Container + // otherwise if truthy, use the supplied render prop + // otherwise if falsey, use EmptyContainer + const Wrapper = + this.props.container === undefined + ? Container + : this.props.container || EmptyContainer; + + let { + hideDefault, + hide = [], + federated, + signUpConfig, + usernameAttributes, + } = this.props; + if (hideDefault) { + hide = hide.concat([ + Greetings, + SignIn, + ConfirmSignIn, + RequireNewPassword, + SignUp, + ConfirmSignUp, + VerifyContact, + ForgotPassword, + TOTPSetup, + Loading, + ]); + } + + let props_children = []; + if (typeof this.props.children === 'object') { + if (Array.isArray(this.props.children)) { + props_children = this.props.children; + } else { + props_children.push(this.props.children); + } + } + + const default_children = [ + , + , + , + , + , + , + , + , + , + , + ]; + + const props_children_override = React.Children.map( + props_children, + child => child.props.override + ); + hide = hide.filter( + component => !props_children.find(child => child.type === component) + ); + + const render_props_children = React.Children.map( + props_children, + (child, index) => { + return React.cloneElement(child, { + key: 'aws-amplify-authenticator-props-children-' + index, + theme, + messageMap, + authState, + authData, + onStateChange: this.handleStateChange, + onAuthEvent: this.handleAuthEvent, + hide, + override: props_children_override, + usernameAttributes, + }); + } + ); + + const render_default_children = hideDefault + ? [] + : React.Children.map(default_children, (child, index) => { + return React.cloneElement(child, { + key: 'aws-amplify-authenticator-default-children-' + index, + theme, + messageMap, + authState, + authData, + onStateChange: this.handleStateChange, + onAuthEvent: this.handleAuthEvent, + hide, + override: props_children_override, + usernameAttributes, + }); + }); + + const render_children = render_default_children.concat( + render_props_children + ); + const error = this.state.error; + + return ( + + {this.state.showToast && ( + this.setState({ showToast: false })} + data-test={auth.signIn.signInError} + > + {I18n.get(error)} + + )} + {render_children} + + ); + } } diff --git a/packages/aws-amplify-react/src/Auth/ConfirmSignIn.jsx b/packages/aws-amplify-react/src/Auth/ConfirmSignIn.jsx index 962d1c1e94d..a079b7041cb 100644 --- a/packages/aws-amplify-react/src/Auth/ConfirmSignIn.jsx +++ b/packages/aws-amplify-react/src/Auth/ConfirmSignIn.jsx @@ -18,17 +18,17 @@ import Auth from '@aws-amplify/auth'; import AuthPiece from './AuthPiece'; import { - FormSection, - FormField, - SectionHeader, - SectionBody, - SectionFooter, - Input, - InputLabel, - Button, - Link, - SectionFooterPrimaryContent, - SectionFooterSecondaryContent, + FormSection, + FormField, + SectionHeader, + SectionBody, + SectionFooter, + Input, + InputLabel, + Button, + Link, + SectionFooterPrimaryContent, + SectionFooterSecondaryContent, } from '../Amplify-UI/Amplify-UI-Components-React'; import { auth } from '../Amplify-UI/data-test-attributes'; @@ -36,96 +36,117 @@ import { auth } from '../Amplify-UI/data-test-attributes'; const logger = new Logger('ConfirmSignIn'); export default class ConfirmSignIn extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this._validAuthStates = ['confirmSignIn']; - this.confirm = this.confirm.bind(this); - this.checkContact = this.checkContact.bind(this); - this.state = { - mfaType: 'SMS' - }; - } + this._validAuthStates = ['confirmSignIn']; + this.confirm = this.confirm.bind(this); + this.checkContact = this.checkContact.bind(this); + this.state = { + mfaType: 'SMS', + }; + } - checkContact(user) { - if (!Auth || typeof Auth.verifiedContact !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } + checkContact(user) { + if (!Auth || typeof Auth.verifiedContact !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } - Auth.verifiedContact(user) - .then(data => { - if (!JS.isEmpty(data.verified)) { - this.changeState('signedIn', user); - } else { - const newUser = Object.assign(user, data); - this.changeState('verifyContact', newUser); - } - }); - } + Auth.verifiedContact(user).then(data => { + if (!JS.isEmpty(data.verified)) { + this.changeState('signedIn', user); + } else { + const newUser = Object.assign(user, data); + this.changeState('verifyContact', newUser); + } + }); + } - confirm(event) { - if (event) { - event.preventDefault(); - }; - const user = this.props.authData; - const { code } = this.inputs; - const mfaType = user.challengeName === 'SOFTWARE_TOKEN_MFA' ? 'SOFTWARE_TOKEN_MFA' : null; - if (!Auth || typeof Auth.confirmSignIn !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } + confirm(event) { + if (event) { + event.preventDefault(); + } + const user = this.props.authData; + const { code } = this.inputs; + const mfaType = + user.challengeName === 'SOFTWARE_TOKEN_MFA' ? 'SOFTWARE_TOKEN_MFA' : null; + if (!Auth || typeof Auth.confirmSignIn !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } - Auth.confirmSignIn(user, code, mfaType) - .then(() => { - this.checkContact(user); - }) - .catch(err => this.error(err)); - } + Auth.confirmSignIn(user, code, mfaType) + .then(() => { + this.checkContact(user); + }) + .catch(err => this.error(err)); + } - componentDidUpdate() { - // logger.debug('component did update with props', this.props); - const user = this.props.authData; - const mfaType = user && user.challengeName === 'SOFTWARE_TOKEN_MFA'? - 'TOTP' : 'SMS'; - if (this.state.mfaType !== mfaType) this.setState({ mfaType }); - } + componentDidUpdate() { + // logger.debug('component did update with props', this.props); + const user = this.props.authData; + const mfaType = + user && user.challengeName === 'SOFTWARE_TOKEN_MFA' ? 'TOTP' : 'SMS'; + if (this.state.mfaType !== mfaType) this.setState({ mfaType }); + } - showComponent(theme) { - const { hide, authData } = this.props; - if (hide && hide.includes(ConfirmSignIn)) { return null; } + showComponent(theme) { + const { hide, authData } = this.props; + if (hide && hide.includes(ConfirmSignIn)) { + return null; + } - return ( - - {I18n.get('Confirm ' + this.state.mfaType + ' Code')} - - - - {I18n.get('Code')} * - - - - - - - - - this.changeState('signIn')} data-test={auth.confirmSignIn.backToSignInLink}> - {I18n.get('Back to Sign In')} - - - - - - ); - } + return ( + + + {I18n.get('Confirm ' + this.state.mfaType + ' Code')} + +
+ + + {I18n.get('Code')} * + + + + + + + + + this.changeState('signIn')} + data-test={auth.confirmSignIn.backToSignInLink} + > + {I18n.get('Back to Sign In')} + + + +
+
+ ); + } } diff --git a/packages/aws-amplify-react/src/Auth/ConfirmSignUp.jsx b/packages/aws-amplify-react/src/Auth/ConfirmSignUp.jsx index b228e23541a..9562b7ab8e7 100644 --- a/packages/aws-amplify-react/src/Auth/ConfirmSignUp.jsx +++ b/packages/aws-amplify-react/src/Auth/ConfirmSignUp.jsx @@ -17,18 +17,18 @@ import Auth from '@aws-amplify/auth'; import AuthPiece from './AuthPiece'; import { - FormSection, - SectionHeader, - SectionBody, - SectionFooter, - Button, - Link, - InputLabel, - Input, - SectionFooterPrimaryContent, - SectionFooterSecondaryContent, - FormField, - Hint, + FormSection, + SectionHeader, + SectionBody, + SectionFooter, + Button, + Link, + InputLabel, + Input, + SectionFooterPrimaryContent, + SectionFooterSecondaryContent, + FormField, + Hint, } from '../Amplify-UI/Amplify-UI-Components-React'; import { auth } from '../Amplify-UI/data-test-attributes'; @@ -36,95 +36,120 @@ import { auth } from '../Amplify-UI/data-test-attributes'; const logger = new Logger('ConfirmSignUp'); export default class ConfirmSignUp extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this._validAuthStates = ['confirmSignUp']; - this.confirm = this.confirm.bind(this); - this.resend = this.resend.bind(this); - } + this._validAuthStates = ['confirmSignUp']; + this.confirm = this.confirm.bind(this); + this.resend = this.resend.bind(this); + } - confirm() { - const username = this.usernameFromAuthData() || this.inputs.username; - const { code } = this.inputs; - if (!Auth || typeof Auth.confirmSignUp !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } + confirm() { + const username = this.usernameFromAuthData() || this.inputs.username; + const { code } = this.inputs; + if (!Auth || typeof Auth.confirmSignUp !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } - Auth.confirmSignUp(username, code) - .then(() => this.changeState('signedUp')) - .catch(err => this.error(err)); - } + Auth.confirmSignUp(username, code) + .then(() => this.changeState('signedUp')) + .catch(err => this.error(err)); + } - resend() { - const username = this.usernameFromAuthData() || this.inputs.username; - if (!Auth || typeof Auth.resendSignUp !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - Auth.resendSignUp(username) - .then(() => logger.debug('code resent')) - .catch(err => this.error(err)); - } + resend() { + const username = this.usernameFromAuthData() || this.inputs.username; + if (!Auth || typeof Auth.resendSignUp !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + Auth.resendSignUp(username) + .then(() => logger.debug('code resent')) + .catch(err => this.error(err)); + } - showComponent(theme) { - const { hide } = this.props; - const username = this.usernameFromAuthData(); + showComponent(theme) { + const { hide } = this.props; + const username = this.usernameFromAuthData(); - if (hide && hide.includes(ConfirmSignUp)) { return null; } + if (hide && hide.includes(ConfirmSignUp)) { + return null; + } - return ( - - - {I18n.get('Confirm Sign Up')} - - - - {I18n.get(this.getUsernameLabel())} * - - + return ( + + + {I18n.get('Confirm Sign Up')} + + + + + {I18n.get(this.getUsernameLabel())} * + + + - - {I18n.get('Confirmation Code')} * - - - {I18n.get('Lost your code? ')} - - {I18n.get('Resend Code')} - - - - - - - - - - this.changeState('signIn')} data-test={auth.confirmSignUp.backToSignInLink}> - {I18n.get('Back to Sign In')} - - - - - ); - } + + + {I18n.get('Confirmation Code')} * + + + + {I18n.get('Lost your code? ')} + + {I18n.get('Resend Code')} + + + + + + + + + + this.changeState('signIn')} + data-test={auth.confirmSignUp.backToSignInLink} + > + {I18n.get('Back to Sign In')} + + + + + ); + } } diff --git a/packages/aws-amplify-react/src/Auth/FederatedSignIn.jsx b/packages/aws-amplify-react/src/Auth/FederatedSignIn.jsx index 40e634a58e4..d891e0e6084 100644 --- a/packages/aws-amplify-react/src/Auth/FederatedSignIn.jsx +++ b/packages/aws-amplify-react/src/Auth/FederatedSignIn.jsx @@ -6,167 +6,203 @@ import Auth from '@aws-amplify/auth'; import AmplifyTheme from '../Amplify-UI/Amplify-UI-Theme'; import { - FormSection, - SectionBody, - Strike, + FormSection, + SectionBody, + Strike, } from '../Amplify-UI/Amplify-UI-Components-React'; import { auth } from '../Amplify-UI/data-test-attributes'; import { - GoogleButton, - FacebookButton, - AmazonButton, - OAuthButton, - Auth0Button + GoogleButton, + FacebookButton, + AmazonButton, + OAuthButton, + Auth0Button, } from './Provider'; const logger = new Logger('FederatedSignIn'); export class FederatedButtons extends Component { - google(google_client_id) { - if (!google_client_id) { return null; } - - const { theme, onStateChange } = this.props; - return ; - } - - facebook(facebook_app_id) { - if (!facebook_app_id) { return null; } - - const { theme, onStateChange } = this.props; - return ; - } - - amazon(amazon_client_id) { - if (!amazon_client_id) { return null; } - - const { theme, onStateChange } = this.props; - return ; - } - - OAuth(oauth_config) { - if (!oauth_config) { return null;} - const { theme, onStateChange } = this.props; - return ; - } - - auth0(auth0) { - if (!auth0) { return null;} - const { theme, onStateChange } = this.props; - return ; - } - - render() { - const { authState } = this.props; - if (!['signIn', 'signedOut', 'signedUp'].includes(authState)) { return null; } - - const federated = this.props.federated || {}; - if (!Auth || typeof Auth.configure !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - - const { oauth={} } = Auth.configure(); - // backward compatibility - if (oauth['domain']) { - federated.oauth_config = Object.assign({}, federated.oauth_config, oauth); - } else if (oauth.awsCognito) { - federated.oauth_config = Object.assign({}, federated.oauth_config, oauth.awsCognito); - } - - if (oauth.auth0) { - federated.auth0 = Object.assign({}, federated.auth0, oauth.auth0); - } - - if (JS.isEmpty(federated)) { return null; } - - const { google_client_id, facebook_app_id, amazon_client_id, oauth_config, auth0 } = federated; - - const theme = this.props.theme || AmplifyTheme; - return ( -
-
- {this.google(google_client_id)} -
-
- {this.facebook(facebook_app_id)} -
-
- {this.amazon(amazon_client_id)} -
-
- {this.OAuth(oauth_config)} -
-
- {this.auth0(auth0)} -
- {I18n.get('or')} -
- ); - } + google(google_client_id) { + if (!google_client_id) { + return null; + } + + const { theme, onStateChange } = this.props; + return ( + + ); + } + + facebook(facebook_app_id) { + if (!facebook_app_id) { + return null; + } + + const { theme, onStateChange } = this.props; + return ( + + ); + } + + amazon(amazon_client_id) { + if (!amazon_client_id) { + return null; + } + + const { theme, onStateChange } = this.props; + return ( + + ); + } + + OAuth(oauth_config) { + if (!oauth_config) { + return null; + } + const { theme, onStateChange } = this.props; + return ( + + ); + } + + auth0(auth0) { + if (!auth0) { + return null; + } + const { theme, onStateChange } = this.props; + return ( + + ); + } + + render() { + const { authState } = this.props; + if (!['signIn', 'signedOut', 'signedUp'].includes(authState)) { + return null; + } + + const federated = this.props.federated || {}; + if (!Auth || typeof Auth.configure !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + + const { oauth = {} } = Auth.configure(); + // backward compatibility + if (oauth['domain']) { + federated.oauth_config = Object.assign({}, federated.oauth_config, oauth); + } else if (oauth.awsCognito) { + federated.oauth_config = Object.assign( + {}, + federated.oauth_config, + oauth.awsCognito + ); + } + + if (oauth.auth0) { + federated.auth0 = Object.assign({}, federated.auth0, oauth.auth0); + } + + if (JS.isEmpty(federated)) { + return null; + } + + const { + google_client_id, + facebook_app_id, + amazon_client_id, + oauth_config, + auth0, + } = federated; + + const theme = this.props.theme || AmplifyTheme; + return ( +
+
{this.google(google_client_id)}
+
{this.facebook(facebook_app_id)}
+
{this.amazon(amazon_client_id)}
+
{this.OAuth(oauth_config)}
+
{this.auth0(auth0)}
+ {I18n.get('or')} +
+ ); + } } export default class FederatedSignIn extends Component { - render() { - const { authState, onStateChange } = this.props; - const federated = this.props.federated || {}; - if (!Auth || typeof Auth.configure !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - - const { oauth={} } = Auth.configure(); - // backward compatibility - if (oauth['domain']) { - federated.oauth_config = Object.assign({}, federated.oauth_config, oauth); - } else if (oauth.awsCognito) { - federated.oauth_config = Object.assign({}, federated.oauth_config, oauth.awsCognito); - } - - if (oauth.auth0) { - federated.auth0 = Object.assign({}, federated.auth0, oauth.auth0); - } - - if (!federated) { - logger.debug('federated prop is empty. show nothing'); - logger.debug('federated={google_client_id: , facebook_app_id: , amazon_client_id}'); - return null; - } - if (!['signIn', 'signedOut', 'signedUp'].includes(authState)) { return null; } - logger.debug('federated Config is', federated); - const theme = this.props.theme || AmplifyTheme; - return ( - - - - - - ); - } + render() { + const { authState, onStateChange } = this.props; + const federated = this.props.federated || {}; + if (!Auth || typeof Auth.configure !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + + const { oauth = {} } = Auth.configure(); + // backward compatibility + if (oauth['domain']) { + federated.oauth_config = Object.assign({}, federated.oauth_config, oauth); + } else if (oauth.awsCognito) { + federated.oauth_config = Object.assign( + {}, + federated.oauth_config, + oauth.awsCognito + ); + } + + if (oauth.auth0) { + federated.auth0 = Object.assign({}, federated.auth0, oauth.auth0); + } + + if (!federated) { + logger.debug('federated prop is empty. show nothing'); + logger.debug( + 'federated={google_client_id: , facebook_app_id: , amazon_client_id}' + ); + return null; + } + if (!['signIn', 'signedOut', 'signedUp'].includes(authState)) { + return null; + } + logger.debug('federated Config is', federated); + const theme = this.props.theme || AmplifyTheme; + return ( + + + + + + ); + } } diff --git a/packages/aws-amplify-react/src/Auth/ForgotPassword.jsx b/packages/aws-amplify-react/src/Auth/ForgotPassword.jsx index bc7c18d7b9e..caf83069f67 100644 --- a/packages/aws-amplify-react/src/Auth/ForgotPassword.jsx +++ b/packages/aws-amplify-react/src/Auth/ForgotPassword.jsx @@ -20,17 +20,17 @@ import AuthPiece from './AuthPiece'; import AmplifyTheme from '../Amplify-UI/Amplify-UI-Theme'; import { - FormSection, - SectionHeader, - SectionBody, - SectionFooter, - Input, - InputLabel, - Button, - FormField, - Link, - SectionFooterPrimaryContent, - SectionFooterSecondaryContent, + FormSection, + SectionHeader, + SectionBody, + SectionFooter, + Input, + InputLabel, + Button, + FormField, + Link, + SectionFooterPrimaryContent, + SectionFooterSecondaryContent, } from '../Amplify-UI/Amplify-UI-Components-React'; import { auth } from '../Amplify-UI/data-test-attributes'; @@ -38,114 +38,147 @@ import { auth } from '../Amplify-UI/data-test-attributes'; const logger = new Logger('ForgotPassword'); export default class ForgotPassword extends AuthPiece { - constructor(props) { - super(props); - - this.send = this.send.bind(this); - this.submit = this.submit.bind(this); - - this._validAuthStates = ['forgotPassword']; - this.state = { delivery: null }; - } - - send() { - const { authData={} } = this.props; - const username = this.getUsernameFromInput() || authData.username; - if (!Auth || typeof Auth.forgotPassword !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - Auth.forgotPassword(username) - .then(data => { - logger.debug(data) - this.setState({ delivery: data.CodeDeliveryDetails }); - }) - .catch(err => this.error(err)); - } - - submit() { - const { authData={} } = this.props; - const { code, password } = this.inputs; - const username = this.getUsernameFromInput() || authData.username; - - if (!Auth || typeof Auth.forgotPasswordSubmit !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - Auth.forgotPasswordSubmit(username, code, password) - .then(data => { - logger.debug(data); - this.changeState('signIn'); - this.setState({ delivery: null }); - }) - .catch(err => this.error(err)); - } - - sendView() { - const theme = this.props.theme || AmplifyTheme; - return ( -
- {this.renderUsernameField(theme)} -
- ); - } - - submitView() { - const theme = this.props.theme || AmplifyTheme; - return ( -
- - {I18n.get('Code')} * - - - - {I18n.get('New Password')} * - - -
- ); - } - - showComponent(theme) { - const { authState, hide, authData={} } = this.props; - if (hide && hide.includes(ForgotPassword)) { return null; } - - return ( - - {I18n.get('Reset your password')} - - { this.state.delivery || authData.username ? this.submitView() : this.sendView() } - - - - { this.state.delivery || authData.username ? - : - - } - - - { this.state.delivery || authData.username ? - {I18n.get('Resend Code')} : - this.changeState('signIn')} data-test={auth.forgotPassword.backToSignInLink}> - {I18n.get('Back to Sign In')} - - } - - - - ); - } + constructor(props) { + super(props); + + this.send = this.send.bind(this); + this.submit = this.submit.bind(this); + + this._validAuthStates = ['forgotPassword']; + this.state = { delivery: null }; + } + + send() { + const { authData = {} } = this.props; + const username = this.getUsernameFromInput() || authData.username; + if (!Auth || typeof Auth.forgotPassword !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + Auth.forgotPassword(username) + .then(data => { + logger.debug(data); + this.setState({ delivery: data.CodeDeliveryDetails }); + }) + .catch(err => this.error(err)); + } + + submit() { + const { authData = {} } = this.props; + const { code, password } = this.inputs; + const username = this.getUsernameFromInput() || authData.username; + + if (!Auth || typeof Auth.forgotPasswordSubmit !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + Auth.forgotPasswordSubmit(username, code, password) + .then(data => { + logger.debug(data); + this.changeState('signIn'); + this.setState({ delivery: null }); + }) + .catch(err => this.error(err)); + } + + sendView() { + const theme = this.props.theme || AmplifyTheme; + return
{this.renderUsernameField(theme)}
; + } + + submitView() { + const theme = this.props.theme || AmplifyTheme; + return ( +
+ + {I18n.get('Code')} * + + + + {I18n.get('New Password')} * + + +
+ ); + } + + showComponent(theme) { + const { authState, hide, authData = {} } = this.props; + if (hide && hide.includes(ForgotPassword)) { + return null; + } + + return ( + + + {I18n.get('Reset your password')} + + + {this.state.delivery || authData.username + ? this.submitView() + : this.sendView()} + + + + {this.state.delivery || authData.username ? ( + + ) : ( + + )} + + + {this.state.delivery || authData.username ? ( + + {I18n.get('Resend Code')} + + ) : ( + this.changeState('signIn')} + data-test={auth.forgotPassword.backToSignInLink} + > + {I18n.get('Back to Sign In')} + + )} + + + + ); + } } diff --git a/packages/aws-amplify-react/src/Auth/Greetings.jsx b/packages/aws-amplify-react/src/Auth/Greetings.jsx index 336b970110b..18f1ed1e17f 100644 --- a/packages/aws-amplify-react/src/Auth/Greetings.jsx +++ b/packages/aws-amplify-react/src/Auth/Greetings.jsx @@ -15,162 +15,189 @@ import * as React from 'react'; import { I18n, ConsoleLogger as Logger, Hub } from '@aws-amplify/core'; import Auth from '@aws-amplify/auth'; import AuthPiece from './AuthPiece'; -import { NavBar, Nav, NavRight, NavItem, NavButton } from '../Amplify-UI/Amplify-UI-Components-React'; +import { + NavBar, + Nav, + NavRight, + NavItem, + NavButton, +} from '../Amplify-UI/Amplify-UI-Components-React'; import { auth } from '../Amplify-UI/data-test-attributes'; import AmplifyTheme from '../Amplify-UI/Amplify-UI-Theme'; import Constants from './common/constants'; import SignOut from './SignOut'; -import { withGoogle, withAmazon, withFacebook, withOAuth, withAuth0 } from './Provider'; +import { + withGoogle, + withAmazon, + withFacebook, + withOAuth, + withAuth0, +} from './Provider'; import { UsernameAttributes } from './common/types'; - const logger = new Logger('Greetings'); export default class Greetings extends AuthPiece { - constructor(props) { - super(props); - this.state = {}; - this.onHubCapsule = this.onHubCapsule.bind(this); - this.inGreeting = this.inGreeting.bind(this); - Hub.listen('auth', this.onHubCapsule); - this._validAuthStates = ['signedIn']; - - } - - componentDidMount() { - this._isMounted = true; - this.findState(); - } - - componentWillUnmount() { - this._isMounted = false; - } - - - findState(){ - if (!this.props.authState && !this.props.authData) { - Auth.currentAuthenticatedUser() - .then(user => { - this.setState({ - authState: 'signedIn', - authData: user, - stateFromStorage: true - }) - }) - .catch(err => logger.debug(err)); - } - } - - onHubCapsule(capsule) { - if (this._isMounted) { - const { channel, payload, source } = capsule; - if (channel === 'auth' && payload.event === 'signIn') { - this.setState({ - authState: 'signedIn', - authData: payload.data - }) - if (!this.props.authState) { - this.setState({stateFromStorage: true}) - } - } else if (channel === 'auth' && payload.event === 'signOut' && (!this.props.authState)) { - this.setState({ - authState: 'signIn' - }); - } - } - } - - inGreeting(name) { - const { usernameAttributes = UsernameAttributes.USERNAME } = this.props; - const prefix = usernameAttributes === UsernameAttributes.USERNAME? `${I18n.get('Hello')} ` : ''; - return `${prefix}${name}`; - } - outGreeting() { return ''; } - - - userGreetings(theme) { - const user = this.props.authData || this.state.authData; - const greeting = this.props.inGreeting || this.inGreeting; - // get name from attributes first - const { usernameAttributes = 'username' } = this.props; - let name = ''; - switch (usernameAttributes) { - case UsernameAttributes.EMAIL: - // Email as Username - name = user.attributes? user.attributes.email : user.username; - break; - case UsernameAttributes.PHONE_NUMBER: - // Phone number as Username - name = user.attributes? user.attributes.phone_number : user.username; - break; - default: - const nameFromAttr = user.attributes? - (user.attributes.name || - (user.attributes.given_name? - (user.attributes.given_name + ' ' + user.attributes.family_name) : undefined)) - : undefined; - name = nameFromAttr || user.name || user.username; - break; - } - - const message = (typeof greeting === 'function')? greeting(name) : greeting; - const { federated } = this.props; - - return ( - - {message} - {this.renderSignOutButton(theme)} - - ); - } - - renderSignOutButton() { - const { federated={} } = this.props; - const { google_client_id, facebook_app_id, amazon_client_id, auth0 } = federated; - const config = Auth.configure(); - const { oauth={} } = config; - const googleClientId = google_client_id || config.googleClientId; - const facebookAppId = facebook_app_id || config.facebookClientId; - const amazonClientId = amazon_client_id || config.amazonClientId; - const auth0_config = auth0 || oauth.auth0; - - if (googleClientId) SignOut = withGoogle(SignOut); - if (facebookAppId) SignOut = withFacebook(SignOut); - if (amazonClientId) SignOut = withAmazon(SignOut); - if (auth0_config) SignOut = withAuth0(SignOut); - - const stateAndProps = Object.assign({}, this.props, this.state); - - return ; - } - - noUserGreetings(theme) { - const greeting = this.props.outGreeting || this.outGreeting; - const message = (typeof greeting === 'function')? greeting() : greeting; - return message? {message} : null; - } - - render() { - const { hide } = this.props; - if (hide && hide.includes(Greetings)) { return null; } - - const authState = this.props.authState || this.state.authState; - const signedIn = (authState === 'signedIn'); - - const theme = this.props.theme || AmplifyTheme; - const greeting = signedIn? this.userGreetings(theme) : this.noUserGreetings(theme); - if (!greeting) { return null; } - - return ( - - - - ); - } + constructor(props) { + super(props); + this.state = {}; + this.onHubCapsule = this.onHubCapsule.bind(this); + this.inGreeting = this.inGreeting.bind(this); + Hub.listen('auth', this.onHubCapsule); + this._validAuthStates = ['signedIn']; + } + + componentDidMount() { + this._isMounted = true; + this.findState(); + } + + componentWillUnmount() { + this._isMounted = false; + } + + findState() { + if (!this.props.authState && !this.props.authData) { + Auth.currentAuthenticatedUser() + .then(user => { + this.setState({ + authState: 'signedIn', + authData: user, + stateFromStorage: true, + }); + }) + .catch(err => logger.debug(err)); + } + } + + onHubCapsule(capsule) { + if (this._isMounted) { + const { channel, payload, source } = capsule; + if (channel === 'auth' && payload.event === 'signIn') { + this.setState({ + authState: 'signedIn', + authData: payload.data, + }); + if (!this.props.authState) { + this.setState({ stateFromStorage: true }); + } + } else if ( + channel === 'auth' && + payload.event === 'signOut' && + !this.props.authState + ) { + this.setState({ + authState: 'signIn', + }); + } + } + } + + inGreeting(name) { + const { usernameAttributes = UsernameAttributes.USERNAME } = this.props; + const prefix = + usernameAttributes === UsernameAttributes.USERNAME + ? `${I18n.get('Hello')} ` + : ''; + return `${prefix}${name}`; + } + outGreeting() { + return ''; + } + + userGreetings(theme) { + const user = this.props.authData || this.state.authData; + const greeting = this.props.inGreeting || this.inGreeting; + // get name from attributes first + const { usernameAttributes = 'username' } = this.props; + let name = ''; + switch (usernameAttributes) { + case UsernameAttributes.EMAIL: + // Email as Username + name = user.attributes ? user.attributes.email : user.username; + break; + case UsernameAttributes.PHONE_NUMBER: + // Phone number as Username + name = user.attributes ? user.attributes.phone_number : user.username; + break; + default: + const nameFromAttr = user.attributes + ? user.attributes.name || + (user.attributes.given_name + ? user.attributes.given_name + ' ' + user.attributes.family_name + : undefined) + : undefined; + name = nameFromAttr || user.name || user.username; + break; + } + + const message = typeof greeting === 'function' ? greeting(name) : greeting; + const { federated } = this.props; + + return ( + + {message} + {this.renderSignOutButton(theme)} + + ); + } + + renderSignOutButton() { + const { federated = {} } = this.props; + const { + google_client_id, + facebook_app_id, + amazon_client_id, + auth0, + } = federated; + const config = Auth.configure(); + const { oauth = {} } = config; + const googleClientId = google_client_id || config.googleClientId; + const facebookAppId = facebook_app_id || config.facebookClientId; + const amazonClientId = amazon_client_id || config.amazonClientId; + const auth0_config = auth0 || oauth.auth0; + + if (googleClientId) SignOut = withGoogle(SignOut); + if (facebookAppId) SignOut = withFacebook(SignOut); + if (amazonClientId) SignOut = withAmazon(SignOut); + if (auth0_config) SignOut = withAuth0(SignOut); + + const stateAndProps = Object.assign({}, this.props, this.state); + + return ; + } + + noUserGreetings(theme) { + const greeting = this.props.outGreeting || this.outGreeting; + const message = typeof greeting === 'function' ? greeting() : greeting; + return message ? {message} : null; + } + + render() { + const { hide } = this.props; + if (hide && hide.includes(Greetings)) { + return null; + } + + const authState = this.props.authState || this.state.authState; + const signedIn = authState === 'signedIn'; + + const theme = this.props.theme || AmplifyTheme; + const greeting = signedIn + ? this.userGreetings(theme) + : this.noUserGreetings(theme); + if (!greeting) { + return null; + } + + return ( + + + + ); + } } diff --git a/packages/aws-amplify-react/src/Auth/Loading.jsx b/packages/aws-amplify-react/src/Auth/Loading.jsx index 332dba5b8d0..c02b93fd1e2 100644 --- a/packages/aws-amplify-react/src/Auth/Loading.jsx +++ b/packages/aws-amplify-react/src/Auth/Loading.jsx @@ -14,12 +14,11 @@ import * as React from 'react'; import { I18n, ConsoleLogger as Logger } from '@aws-amplify/core'; - import AuthPiece from './AuthPiece'; import AmplifyTheme from '../AmplifyTheme'; import { - FormSection, - SectionBody + FormSection, + SectionBody, } from '../Amplify-UI/Amplify-UI-Components-React'; import { auth } from '../Amplify-UI/data-test-attributes'; @@ -27,21 +26,22 @@ import { auth } from '../Amplify-UI/data-test-attributes'; const logger = new Logger('Loading'); export default class Loading extends AuthPiece { - constructor(props) { - super(props); - - this._validAuthStates = ['loading']; - } - - showComponent(theme) { - const { hide } = this.props; - if (hide && hide.includes(Loading)) { return null; } - - return ( - - {I18n.get('Loading...')} - - - ); - } + constructor(props) { + super(props); + + this._validAuthStates = ['loading']; + } + + showComponent(theme) { + const { hide } = this.props; + if (hide && hide.includes(Loading)) { + return null; + } + + return ( + + {I18n.get('Loading...')} + + ); + } } diff --git a/packages/aws-amplify-react/src/Auth/PhoneField.jsx b/packages/aws-amplify-react/src/Auth/PhoneField.jsx index ac68a2368e4..72a13ab4910 100644 --- a/packages/aws-amplify-react/src/Auth/PhoneField.jsx +++ b/packages/aws-amplify-react/src/Auth/PhoneField.jsx @@ -1,82 +1,88 @@ import * as React from 'react'; -import { - FormField, - Input, - InputLabel, - SelectInput - } from '../Amplify-UI/Amplify-UI-Components-React'; +import { + FormField, + Input, + InputLabel, + SelectInput, +} from '../Amplify-UI/Amplify-UI-Components-React'; import AmplifyTheme from '../Amplify-UI/Amplify-UI-Theme'; import countryDialCodes from './common/country-dial-codes.js'; import { I18n } from '@aws-amplify/core'; import { auth } from '../Amplify-UI/data-test-attributes'; class PhoneField extends React.Component { - constructor(props) { - super(props); - this.handleInputChange = this.handleInputChange.bind(this); - this.composePhoneNumber = this.composePhoneNumber.bind(this); + constructor(props) { + super(props); + this.handleInputChange = this.handleInputChange.bind(this); + this.composePhoneNumber = this.composePhoneNumber.bind(this); - this.inputs = { - dial_code: this.props.defaultDialCode || '+1', - phone_line_number: '' - } - } + this.inputs = { + dial_code: this.props.defaultDialCode || '+1', + phone_line_number: '', + }; + } - composePhoneNumber(dial_code, phone_line_number) { - return `${dial_code || '+1'}${phone_line_number.replace(/[-()]/g, '')}`; - } + composePhoneNumber(dial_code, phone_line_number) { + return `${dial_code || '+1'}${phone_line_number.replace(/[-()]/g, '')}`; + } - handleInputChange(evt) { - const { name, value } = evt.target; - this.inputs[name] = value; + handleInputChange(evt) { + const { name, value } = evt.target; + this.inputs[name] = value; - if (this.props.onChangeText) { - this.props.onChangeText( - this.composePhoneNumber(this.inputs.dial_code, this.inputs.phone_line_number) - ); - } - } + if (this.props.onChangeText) { + this.props.onChangeText( + this.composePhoneNumber( + this.inputs.dial_code, + this.inputs.phone_line_number + ) + ); + } + } - render() { - const { - theme=AmplifyTheme, - required=true, - defaultDialCode='+1', - label='Phone Number', - placeholder='Enter your phone number' - } = this.props; - - return ( - - { - required ? - {I18n.get(label)} * : - {I18n.get(label)} - } - - - - - - ) - } + render() { + const { + theme = AmplifyTheme, + required = true, + defaultDialCode = '+1', + label = 'Phone Number', + placeholder = 'Enter your phone number', + } = this.props; + + return ( + + {required ? ( + {I18n.get(label)} * + ) : ( + {I18n.get(label)} + )} + + + + + + ); + } } export { PhoneField }; diff --git a/packages/aws-amplify-react/src/Auth/Provider/index.jsx b/packages/aws-amplify-react/src/Auth/Provider/index.jsx index 5aa20d62eae..4a7a05112a4 100644 --- a/packages/aws-amplify-react/src/Auth/Provider/index.jsx +++ b/packages/aws-amplify-react/src/Auth/Provider/index.jsx @@ -27,14 +27,14 @@ export { default as withOAuth, OAuthButton } from './withOAuth'; export { default as withAuth0, Auth0Button } from './withAuth0'; export function withFederated(Comp) { - const Federated = withAuth0(withOAuth(withAmazon(withGoogle(withFacebook(Comp))))); + const Federated = withAuth0( + withOAuth(withAmazon(withGoogle(withFacebook(Comp)))) + ); - return class extends Component { - render() { - const federated = this.props.federated || {}; - return ( - - ); - } - }; + return class extends Component { + render() { + const federated = this.props.federated || {}; + return ; + } + }; } diff --git a/packages/aws-amplify-react/src/Auth/Provider/withAmazon.jsx b/packages/aws-amplify-react/src/Auth/Provider/withAmazon.jsx index 6f343a3a2cb..d2d5baa31c7 100644 --- a/packages/aws-amplify-react/src/Auth/Provider/withAmazon.jsx +++ b/packages/aws-amplify-react/src/Auth/Provider/withAmazon.jsx @@ -18,141 +18,166 @@ import { I18n, ConsoleLogger as Logger } from '@aws-amplify/core'; import Auth from '@aws-amplify/auth'; import AmplifyTheme from '../../Amplify-UI/Amplify-UI-Theme'; import { amazonSignInButton } from '@aws-amplify/ui'; -import { - SignInButton, - SignInButtonIcon, - SignInButtonContent +import { + SignInButton, + SignInButtonIcon, + SignInButtonContent, } from '../../Amplify-UI/Amplify-UI-Components-React'; import Constants from '../common/constants'; const logger = new Logger('withAmazon'); export default function withAmazon(Comp) { - return class extends Component { - constructor(props) { - super(props); - - this.initAmazon = this.initAmazon.bind(this); - this.signIn = this.signIn.bind(this); - this.signOut = this.signOut.bind(this); - this.federatedSignIn = this.federatedSignIn.bind(this); - - this.state = {}; - } - - signIn() { - const amz = window.amazon; - const options = { scope: 'profile' }; - amz.Login.authorize(options, (response) => { - if (response.error) { - logger.debug('Failed to login with amazon: ' + response.error); - return; - } - - const payload = { - provider: Constants.AMAZON - }; - try { - localStorage.setItem(Constants.AUTH_SOURCE_KEY, JSON.stringify(payload)); - } catch (e) { - logger.debug('Failed to cache auth source into localStorage', e); - } - - this.federatedSignIn(response); - }); - } - - federatedSignIn(response) { - const { access_token, expires_in } = response; - const { onStateChange } = this.props; - const date = new Date(); - const expires_at = expires_in * 1000 + date.getTime(); - if (!access_token) { - return; - } - - const amz = window.amazon; - amz.Login.retrieveProfile((userInfo) => { - if (!userInfo.success) { - logger.debug('Get user Info failed'); - return; - } - - const user = { - name: userInfo.profile.Name, - email: userInfo.profile.PrimaryEmail - }; - if (!Auth || - typeof Auth.federatedSignIn !== 'function' || - typeof Auth.currentAuthenticatedUser !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - - Auth.federatedSignIn('amazon', { token: access_token, expires_at }, user) - .then(credentials => { - return Auth.currentAuthenticatedUser(); - }).then(authUser => { - if (onStateChange) { - onStateChange('signedIn', authUser); - } - }); - }); - } - - signOut() { - const amz = window.amazon; - if (!amz) { - logger.debug('Amazon Login sdk undefined'); - return Promise.resolve(); - } - - logger.debug('Amazon signing out'); - amz.Login.logout(); - } - - componentDidMount() { - const { amazon_client_id } = this.props; - if (amazon_client_id && !window.amazon) this.createScript(); - } - - createScript() { - const script = document.createElement('script'); - script.src = 'https://api-cdn.amazon.com/sdk/login1.js'; - script.async = true; - script.onload = this.initAmazon; - document.body.appendChild(script); - } - - initAmazon() { - logger.debug('init amazon'); - const { amazon_client_id } = this.props; - const amz = window.amazon; - amz.Login.setClientId(amazon_client_id); - } - - render() { - const amz = window.amazon; - return ( - - ); - } - }; + return class extends Component { + constructor(props) { + super(props); + + this.initAmazon = this.initAmazon.bind(this); + this.signIn = this.signIn.bind(this); + this.signOut = this.signOut.bind(this); + this.federatedSignIn = this.federatedSignIn.bind(this); + + this.state = {}; + } + + signIn() { + const amz = window.amazon; + const options = { scope: 'profile' }; + amz.Login.authorize(options, response => { + if (response.error) { + logger.debug('Failed to login with amazon: ' + response.error); + return; + } + + const payload = { + provider: Constants.AMAZON, + }; + try { + localStorage.setItem( + Constants.AUTH_SOURCE_KEY, + JSON.stringify(payload) + ); + } catch (e) { + logger.debug('Failed to cache auth source into localStorage', e); + } + + this.federatedSignIn(response); + }); + } + + federatedSignIn(response) { + const { access_token, expires_in } = response; + const { onStateChange } = this.props; + const date = new Date(); + const expires_at = expires_in * 1000 + date.getTime(); + if (!access_token) { + return; + } + + const amz = window.amazon; + amz.Login.retrieveProfile(userInfo => { + if (!userInfo.success) { + logger.debug('Get user Info failed'); + return; + } + + const user = { + name: userInfo.profile.Name, + email: userInfo.profile.PrimaryEmail, + }; + if ( + !Auth || + typeof Auth.federatedSignIn !== 'function' || + typeof Auth.currentAuthenticatedUser !== 'function' + ) { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + + Auth.federatedSignIn( + 'amazon', + { token: access_token, expires_at }, + user + ) + .then(credentials => { + return Auth.currentAuthenticatedUser(); + }) + .then(authUser => { + if (onStateChange) { + onStateChange('signedIn', authUser); + } + }); + }); + } + + signOut() { + const amz = window.amazon; + if (!amz) { + logger.debug('Amazon Login sdk undefined'); + return Promise.resolve(); + } + + logger.debug('Amazon signing out'); + amz.Login.logout(); + } + + componentDidMount() { + const { amazon_client_id } = this.props; + if (amazon_client_id && !window.amazon) this.createScript(); + } + + createScript() { + const script = document.createElement('script'); + script.src = 'https://api-cdn.amazon.com/sdk/login1.js'; + script.async = true; + script.onload = this.initAmazon; + document.body.appendChild(script); + } + + initAmazon() { + logger.debug('init amazon'); + const { amazon_client_id } = this.props; + const amz = window.amazon; + amz.Login.setClientId(amazon_client_id); + } + + render() { + const amz = window.amazon; + return ( + + ); + } + }; } -const Button = (props) => ( - - - - - - {I18n.get('Sign In with Amazon')} - - +const Button = props => ( + + + + + + + + + + {I18n.get('Sign In with Amazon')} + + ); export const AmazonButton = withAmazon(Button); diff --git a/packages/aws-amplify-react/src/Auth/Provider/withAuth0.jsx b/packages/aws-amplify-react/src/Auth/Provider/withAuth0.jsx index 1e92832161c..f52bbe9affd 100644 --- a/packages/aws-amplify-react/src/Auth/Provider/withAuth0.jsx +++ b/packages/aws-amplify-react/src/Auth/Provider/withAuth0.jsx @@ -11,8 +11,8 @@ * and limitations under the License. */ - import * as React from 'react'; - import { Component } from 'react'; +import * as React from 'react'; +import { Component } from 'react'; import { ConsoleLogger as Logger } from '@aws-amplify/core'; import Auth from '@aws-amplify/auth'; @@ -20,154 +20,173 @@ import AmplifyTheme from '../../Amplify-UI/Amplify-UI-Theme'; // import auth0 from 'auth0-js'; import { auth0SignInButton } from '@aws-amplify/ui'; import { - SignInButton, - SignInButtonIcon, - SignInButtonContent + SignInButton, + SignInButtonIcon, + SignInButtonContent, } from '../../Amplify-UI/Amplify-UI-Components-React'; import Constants from '../common/constants'; - const logger = new Logger('withAuth0'); export default function withAuth0(Comp, options) { - return class extends Component { - constructor(props) { - super(props); - this._auth0 = null; - - this.initialize = this.initialize.bind(this); - this.signIn = this.signIn.bind(this); - this.signOut = this.signOut.bind(this); - } - - componentDidMount() { - if (!window.auth0) { - this.createScript(); - } else { - this.initialize(); - } - } - - createScript() { - const script = document.createElement('script'); - script.src = 'https://cdn.auth0.com/js/auth0/9.8.1/auth0.min.js'; - script.async = true; - script.onload = this.initialize; - document.body.appendChild(script); - } - - initialize() { - const { oauth = {} } = Auth.configure(); - const config = this.props.auth0 || options || oauth.auth0; - const { onError, onStateChange, authState, onAuthEvent } = this.props; - if (!config) { - logger.debug('Auth0 is not configured'); - return; - } - - logger.debug('withAuth0 configuration', config); - - if (!this._auth0) { - this._auth0 = new window['auth0'].WebAuth(config); - window.auth0_client = this._auth0; - } - - if (authState !== 'signedIn') { - this._auth0.parseHash((err, authResult) => { - if (err || !authResult) { - logger.debug('Failed to parse the url for Auth0', err); - return; - } - const payload = { - provider: Constants.AUTH0, - opts: { - returnTo: config.returnTo, - clientID: config.clientID, - federated: config.federated - } - }; - - try { - localStorage.setItem(Constants.AUTH_SOURCE_KEY, JSON.stringify(payload)); - } catch (e) { - logger.debug('Failed to cache auth source into localStorage', e); - } - - this._auth0.client.userInfo(authResult.accessToken, (err, user) => { - let username = undefined; - let email = undefined; - if (err) { - logger.debug('Failed to get the user info', err); - } else { - username = user.name; - email = user.email; - } - - Auth.federatedSignIn( - config.domain, - { - token: authResult.idToken, - expires_at: authResult.expiresIn * 1000 + new Date().getTime() - }, - { name: username, email } - ).then((cred) => { - if (onStateChange) { - Auth.currentAuthenticatedUser().then(user => { - onStateChange('signedIn', user); - }); - } - }).catch((e) => { - logger.debug('Failed to get the aws credentials', e); - if (onError) onError(e); - }); - }); - }); - } - } - - async signIn() { - if (this._auth0) this._auth0.authorize(); - else { - throw new Error('the auth0 client is not configured'); - } - } - - signOut(opts={}) { - const auth0 = window.auth0_client; - const { returnTo, clientID, federated } = opts; - if (!auth0) { - logger.debug('auth0 sdk undefined'); - return Promise.resolve(); - } - auth0.logout({ - returnTo, - clientID, - federated - }); - } - - render() { - return ; - } - }; + return class extends Component { + constructor(props) { + super(props); + this._auth0 = null; + + this.initialize = this.initialize.bind(this); + this.signIn = this.signIn.bind(this); + this.signOut = this.signOut.bind(this); + } + + componentDidMount() { + if (!window.auth0) { + this.createScript(); + } else { + this.initialize(); + } + } + + createScript() { + const script = document.createElement('script'); + script.src = 'https://cdn.auth0.com/js/auth0/9.8.1/auth0.min.js'; + script.async = true; + script.onload = this.initialize; + document.body.appendChild(script); + } + + initialize() { + const { oauth = {} } = Auth.configure(); + const config = this.props.auth0 || options || oauth.auth0; + const { onError, onStateChange, authState, onAuthEvent } = this.props; + if (!config) { + logger.debug('Auth0 is not configured'); + return; + } + + logger.debug('withAuth0 configuration', config); + + if (!this._auth0) { + this._auth0 = new window['auth0'].WebAuth(config); + window.auth0_client = this._auth0; + } + + if (authState !== 'signedIn') { + this._auth0.parseHash((err, authResult) => { + if (err || !authResult) { + logger.debug('Failed to parse the url for Auth0', err); + return; + } + const payload = { + provider: Constants.AUTH0, + opts: { + returnTo: config.returnTo, + clientID: config.clientID, + federated: config.federated, + }, + }; + + try { + localStorage.setItem( + Constants.AUTH_SOURCE_KEY, + JSON.stringify(payload) + ); + } catch (e) { + logger.debug('Failed to cache auth source into localStorage', e); + } + + this._auth0.client.userInfo(authResult.accessToken, (err, user) => { + let username = undefined; + let email = undefined; + if (err) { + logger.debug('Failed to get the user info', err); + } else { + username = user.name; + email = user.email; + } + + Auth.federatedSignIn( + config.domain, + { + token: authResult.idToken, + expires_at: authResult.expiresIn * 1000 + new Date().getTime(), + }, + { name: username, email } + ) + .then(cred => { + if (onStateChange) { + Auth.currentAuthenticatedUser().then(user => { + onStateChange('signedIn', user); + }); + } + }) + .catch(e => { + logger.debug('Failed to get the aws credentials', e); + if (onError) onError(e); + }); + }); + }); + } + } + + async signIn() { + if (this._auth0) this._auth0.authorize(); + else { + throw new Error('the auth0 client is not configured'); + } + } + + signOut(opts = {}) { + const auth0 = window.auth0_client; + const { returnTo, clientID, federated } = opts; + if (!auth0) { + logger.debug('auth0 sdk undefined'); + return Promise.resolve(); + } + auth0.logout({ + returnTo, + clientID, + federated, + }); + } + + render() { + return ( + + ); + } + }; } const Button = props => ( - - - - - - - - {props.label || 'Sign In with Auth0'} - - + + + + + + + + {props.label || 'Sign In with Auth0'} + + ); export const Auth0Button = withAuth0(Button); diff --git a/packages/aws-amplify-react/src/Auth/Provider/withFacebook.jsx b/packages/aws-amplify-react/src/Auth/Provider/withFacebook.jsx index ce0f83b0564..41a578caed7 100644 --- a/packages/aws-amplify-react/src/Auth/Provider/withFacebook.jsx +++ b/packages/aws-amplify-react/src/Auth/Provider/withFacebook.jsx @@ -18,173 +18,199 @@ import { I18n, ConsoleLogger as Logger } from '@aws-amplify/core'; import Auth from '@aws-amplify/auth'; import AmplifyTheme from '../../Amplify-UI/Amplify-UI-Theme'; import { facebookSignInButton } from '@aws-amplify/ui'; -import { - SignInButton, - SignInButtonIcon, - SignInButtonContent +import { + SignInButton, + SignInButtonIcon, + SignInButtonContent, } from '../../Amplify-UI/Amplify-UI-Components-React'; import Constants from '../common/constants'; const logger = new Logger('withFacebook'); export default function withFacebook(Comp) { - return class extends Component { - constructor(props) { - super(props); - - this.fbAsyncInit = this.fbAsyncInit.bind(this); - this.initFB = this.initFB.bind(this); - this.signIn = this.signIn.bind(this); - this.signOut = this.signOut.bind(this); - this.federatedSignIn = this.federatedSignIn.bind(this); - - this.state = {}; - } - - signIn() { - const fb = window.FB; - - fb.getLoginStatus(response => { - const payload = { - provider: Constants.FACEBOOK - }; - try { - localStorage.setItem(Constants.AUTH_SOURCE_KEY, JSON.stringify(payload)); - } catch (e) { - logger.debug('Failed to cache auth source into localStorage', e); - } - - if (response.status === 'connected') { - this.federatedSignIn(response.authResponse); - } else { - fb.login( - response => { - if (!response || !response.authResponse) { - return; - } - this.federatedSignIn(response.authResponse); - }, - { - scope: 'public_profile,email' - } - ); - } - }); - } - - federatedSignIn(response) { - logger.debug(response); - const { onStateChange } = this.props; - - const { accessToken, expiresIn } = response; - const date = new Date(); - const expires_at = expiresIn * 1000 + date.getTime(); - if (!accessToken) { - return; - } - - const fb = window.FB; - fb.api('/me', { fields: 'name,email' }, response => { - const user = { - name: response.name, - email: response.email - }; - if (!Auth || - typeof Auth.federatedSignIn !== 'function' || - typeof Auth.currentAuthenticatedUser !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - - Auth.federatedSignIn('facebook', { token: accessToken, expires_at }, user) - .then(credentials => { - return Auth.currentAuthenticatedUser(); - }).then(authUser => { - if (onStateChange) { - onStateChange('signedIn', authUser); - } - }); - }); - } - - signOut() { - const fb = window.FB; - if (!fb) { - logger.debug('FB sdk undefined'); - return Promise.resolve(); - } - - fb.getLoginStatus(response => { - if (response.status === 'connected') { - return new Promise((res, rej) => { - logger.debug('facebook signing out'); - fb.logout(response => { - res(response); - }); - }); - } else { - return Promise.resolve(); - } - }); - } - - componentDidMount() { - const { facebook_app_id } = this.props; - if (facebook_app_id && !window.FB) this.createScript(); - } - - fbAsyncInit() { - logger.debug('init FB'); - - const { facebook_app_id } = this.props; - const fb = window.FB; - fb.init({ - appId : facebook_app_id, - cookie : true, - xfbml : true, - version : 'v2.11' - }); - - fb.getLoginStatus(response => logger.debug(response)); - } - - initFB() { - const fb = window.FB; - logger.debug('FB inited'); - } - - createScript() { - window.fbAsyncInit = this.fbAsyncInit; - - const script = document.createElement('script'); - script.src = 'https://connect.facebook.net/en_US/sdk.js'; - script.async = true; - script.onload = this.initFB; - document.body.appendChild(script); - } - - render() { - const fb = window.FB; - return ( - - ); - } - }; + return class extends Component { + constructor(props) { + super(props); + + this.fbAsyncInit = this.fbAsyncInit.bind(this); + this.initFB = this.initFB.bind(this); + this.signIn = this.signIn.bind(this); + this.signOut = this.signOut.bind(this); + this.federatedSignIn = this.federatedSignIn.bind(this); + + this.state = {}; + } + + signIn() { + const fb = window.FB; + + fb.getLoginStatus(response => { + const payload = { + provider: Constants.FACEBOOK, + }; + try { + localStorage.setItem( + Constants.AUTH_SOURCE_KEY, + JSON.stringify(payload) + ); + } catch (e) { + logger.debug('Failed to cache auth source into localStorage', e); + } + + if (response.status === 'connected') { + this.federatedSignIn(response.authResponse); + } else { + fb.login( + response => { + if (!response || !response.authResponse) { + return; + } + this.federatedSignIn(response.authResponse); + }, + { + scope: 'public_profile,email', + } + ); + } + }); + } + + federatedSignIn(response) { + logger.debug(response); + const { onStateChange } = this.props; + + const { accessToken, expiresIn } = response; + const date = new Date(); + const expires_at = expiresIn * 1000 + date.getTime(); + if (!accessToken) { + return; + } + + const fb = window.FB; + fb.api('/me', { fields: 'name,email' }, response => { + const user = { + name: response.name, + email: response.email, + }; + if ( + !Auth || + typeof Auth.federatedSignIn !== 'function' || + typeof Auth.currentAuthenticatedUser !== 'function' + ) { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + + Auth.federatedSignIn( + 'facebook', + { token: accessToken, expires_at }, + user + ) + .then(credentials => { + return Auth.currentAuthenticatedUser(); + }) + .then(authUser => { + if (onStateChange) { + onStateChange('signedIn', authUser); + } + }); + }); + } + + signOut() { + const fb = window.FB; + if (!fb) { + logger.debug('FB sdk undefined'); + return Promise.resolve(); + } + + fb.getLoginStatus(response => { + if (response.status === 'connected') { + return new Promise((res, rej) => { + logger.debug('facebook signing out'); + fb.logout(response => { + res(response); + }); + }); + } else { + return Promise.resolve(); + } + }); + } + + componentDidMount() { + const { facebook_app_id } = this.props; + if (facebook_app_id && !window.FB) this.createScript(); + } + + fbAsyncInit() { + logger.debug('init FB'); + + const { facebook_app_id } = this.props; + const fb = window.FB; + fb.init({ + appId: facebook_app_id, + cookie: true, + xfbml: true, + version: 'v2.11', + }); + + fb.getLoginStatus(response => logger.debug(response)); + } + + initFB() { + const fb = window.FB; + logger.debug('FB inited'); + } + + createScript() { + window.fbAsyncInit = this.fbAsyncInit; + + const script = document.createElement('script'); + script.src = 'https://connect.facebook.net/en_US/sdk.js'; + script.async = true; + script.onload = this.initFB; + document.body.appendChild(script); + } + + render() { + const fb = window.FB; + return ( + + ); + } + }; } -const Button = (props) => ( - - - - - - {I18n.get('Sign In with Facebook')} - - +const Button = props => ( + + + + + + + + + + + + {I18n.get('Sign In with Facebook')} + + ); export const FacebookButton = withFacebook(Button); diff --git a/packages/aws-amplify-react/src/Auth/Provider/withGoogle.jsx b/packages/aws-amplify-react/src/Auth/Provider/withGoogle.jsx index 12ed69698fe..2257f97694a 100644 --- a/packages/aws-amplify-react/src/Auth/Provider/withGoogle.jsx +++ b/packages/aws-amplify-react/src/Auth/Provider/withGoogle.jsx @@ -19,150 +19,189 @@ import Auth from '@aws-amplify/auth'; import AmplifyTheme from '../../Amplify-UI/Amplify-UI-Theme'; import { googleSignInButton } from '@aws-amplify/ui'; import { - SignInButton, - SignInButtonIcon, - SignInButtonContent + SignInButton, + SignInButtonIcon, + SignInButtonContent, } from '../../Amplify-UI/Amplify-UI-Components-React'; import Constants from '../common/constants'; const logger = new Logger('withGoogle'); export default function withGoogle(Comp) { - return class extends Component { - constructor(props) { - super(props); - - this.initGapi = this.initGapi.bind(this); - this.signIn = this.signIn.bind(this); - this.signOut = this.signOut.bind(this); - this.federatedSignIn = this.federatedSignIn.bind(this); - - this.state = {}; - } - - signIn() { - const ga = window.gapi.auth2.getAuthInstance(); - const { onError } = this.props; - ga.signIn().then( - googleUser => { - this.federatedSignIn(googleUser); - const payload = { - provider: Constants.GOOGLE - }; - - try { - localStorage.setItem(Constants.AUTH_SOURCE_KEY, JSON.stringify(payload)); - } catch (e) { - logger.debug('Failed to cache auth source into localStorage', e); - } - }, - error => { - if (onError) onError(error); - else throw error; - } - ); - } - - async federatedSignIn(googleUser) { - const { id_token, expires_at } = googleUser.getAuthResponse(); - const profile = googleUser.getBasicProfile(); - let user = { - email: profile.getEmail(), - name: profile.getName(), - picture: profile.getImageUrl(), - }; - - const { onStateChange } = this.props; - if (!Auth || - typeof Auth.federatedSignIn !== 'function' || - typeof Auth.currentAuthenticatedUser !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - - await Auth.federatedSignIn( - 'google', - { token: id_token, expires_at }, - user - ); - - user = await Auth.currentAuthenticatedUser(); - - if (onStateChange) { - onStateChange('signedIn', user); - } - } - - signOut() { - const authInstance = window.gapi && window.gapi.auth2? window.gapi.auth2.getAuthInstance() : null; - if (!authInstance) { - return Promise.resolve(); - } - - authInstance.then((googleAuth) => { - if (!googleAuth) { - logger.debug('google Auth undefined'); - return Promise.resolve(); - } - - logger.debug('google signing out'); - return googleAuth.signOut(); - }); - } - - componentDidMount() { - const { google_client_id } = this.props; - const ga = window.gapi && window.gapi.auth2 ? - window.gapi.auth2.getAuthInstance() : - null; - if (google_client_id && !ga) this.createScript(); - } - - createScript() { - const script = document.createElement('script'); - script.src = 'https://apis.google.com/js/platform.js'; - script.async = true; - script.onload = this.initGapi; - document.body.appendChild(script); - } - - initGapi() { - logger.debug('init gapi'); - - const that = this; - const { google_client_id } = this.props; - const g = window.gapi; - g.load('auth2', function() { - g.auth2.init({ - client_id: google_client_id, - scope: 'profile email openid' - }); - }); - } - - render() { - const ga = - window.gapi && window.gapi.auth2 - ? window.gapi.auth2.getAuthInstance() - : null; - return ; - } - }; + return class extends Component { + constructor(props) { + super(props); + + this.initGapi = this.initGapi.bind(this); + this.signIn = this.signIn.bind(this); + this.signOut = this.signOut.bind(this); + this.federatedSignIn = this.federatedSignIn.bind(this); + + this.state = {}; + } + + signIn() { + const ga = window.gapi.auth2.getAuthInstance(); + const { onError } = this.props; + ga.signIn().then( + googleUser => { + this.federatedSignIn(googleUser); + const payload = { + provider: Constants.GOOGLE, + }; + + try { + localStorage.setItem( + Constants.AUTH_SOURCE_KEY, + JSON.stringify(payload) + ); + } catch (e) { + logger.debug('Failed to cache auth source into localStorage', e); + } + }, + error => { + if (onError) onError(error); + else throw error; + } + ); + } + + async federatedSignIn(googleUser) { + const { id_token, expires_at } = googleUser.getAuthResponse(); + const profile = googleUser.getBasicProfile(); + let user = { + email: profile.getEmail(), + name: profile.getName(), + picture: profile.getImageUrl(), + }; + + const { onStateChange } = this.props; + if ( + !Auth || + typeof Auth.federatedSignIn !== 'function' || + typeof Auth.currentAuthenticatedUser !== 'function' + ) { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + + await Auth.federatedSignIn( + 'google', + { token: id_token, expires_at }, + user + ); + + user = await Auth.currentAuthenticatedUser(); + + if (onStateChange) { + onStateChange('signedIn', user); + } + } + + signOut() { + const authInstance = + window.gapi && window.gapi.auth2 + ? window.gapi.auth2.getAuthInstance() + : null; + if (!authInstance) { + return Promise.resolve(); + } + + authInstance.then(googleAuth => { + if (!googleAuth) { + logger.debug('google Auth undefined'); + return Promise.resolve(); + } + + logger.debug('google signing out'); + return googleAuth.signOut(); + }); + } + + componentDidMount() { + const { google_client_id } = this.props; + const ga = + window.gapi && window.gapi.auth2 + ? window.gapi.auth2.getAuthInstance() + : null; + if (google_client_id && !ga) this.createScript(); + } + + createScript() { + const script = document.createElement('script'); + script.src = 'https://apis.google.com/js/platform.js'; + script.async = true; + script.onload = this.initGapi; + document.body.appendChild(script); + } + + initGapi() { + logger.debug('init gapi'); + + const that = this; + const { google_client_id } = this.props; + const g = window.gapi; + g.load('auth2', function() { + g.auth2.init({ + client_id: google_client_id, + scope: 'profile email openid', + }); + }); + } + + render() { + const ga = + window.gapi && window.gapi.auth2 + ? window.gapi.auth2.getAuthInstance() + : null; + return ( + + ); + } + }; } const Button = props => ( - - - - - - {I18n.get('Sign In with Google')} - - + + + + + + + + + + + {I18n.get('Sign In with Google')} + + ); export const GoogleButton = withGoogle(Button); diff --git a/packages/aws-amplify-react/src/Auth/Provider/withOAuth.jsx b/packages/aws-amplify-react/src/Auth/Provider/withOAuth.jsx index 4bf661ea01a..5f9da531996 100644 --- a/packages/aws-amplify-react/src/Auth/Provider/withOAuth.jsx +++ b/packages/aws-amplify-react/src/Auth/Provider/withOAuth.jsx @@ -18,41 +18,39 @@ import { I18n, ConsoleLogger as Logger } from '@aws-amplify/core'; import Auth from '@aws-amplify/auth'; import AmplifyTheme from '../../Amplify-UI/Amplify-UI-Theme'; import { oAuthSignInButton } from '@aws-amplify/ui'; -import { - SignInButton, - SignInButtonContent +import { + SignInButton, + SignInButtonContent, } from '../../Amplify-UI/Amplify-UI-Components-React'; export default function withOAuth(Comp) { - return class extends Component { - constructor(props) { - super(props); - this.signIn = this.signIn.bind(this); - } + return class extends Component { + constructor(props) { + super(props); + this.signIn = this.signIn.bind(this); + } - signIn(_e, provider) { - Auth.federatedSignIn({ provider }); - } + signIn(_e, provider) { + Auth.federatedSignIn({ provider }); + } - render() { - return ( - - ); - } - }; + render() { + return ; + } + }; } -const Button = (props) => ( - props.OAuthSignIn()} - theme={props.theme || AmplifyTheme} - variant={'oAuthSignInButton'} - > - - {I18n.get(props.label || 'Sign in with AWS')} - - +const Button = props => ( + props.OAuthSignIn()} + theme={props.theme || AmplifyTheme} + variant={'oAuthSignInButton'} + > + + {I18n.get(props.label || 'Sign in with AWS')} + + ); export const OAuthButton = withOAuth(Button); diff --git a/packages/aws-amplify-react/src/Auth/RequireNewPassword.jsx b/packages/aws-amplify-react/src/Auth/RequireNewPassword.jsx index 462eed5ca26..1db8d01e8e9 100644 --- a/packages/aws-amplify-react/src/Auth/RequireNewPassword.jsx +++ b/packages/aws-amplify-react/src/Auth/RequireNewPassword.jsx @@ -19,15 +19,15 @@ import Auth from '@aws-amplify/auth'; import AuthPiece from './AuthPiece'; import AmplifyTheme from '../AmplifyTheme'; import { - FormSection, - SectionHeader, - SectionBody, - SectionFooter, - Input, - Button, - Link, - SectionFooterPrimaryContent, - SectionFooterSecondaryContent, + FormSection, + SectionHeader, + SectionBody, + SectionFooter, + Input, + Button, + Link, + SectionFooterPrimaryContent, + SectionFooterSecondaryContent, } from '../Amplify-UI/Amplify-UI-Components-React'; import { auth } from '../Amplify-UI/data-test-attributes'; @@ -35,123 +35,137 @@ import { auth } from '../Amplify-UI/data-test-attributes'; const logger = new Logger('RequireNewPassword'); export default class RequireNewPassword extends AuthPiece { - constructor(props) { - super(props); - - this._validAuthStates = ['requireNewPassword']; - this.change = this.change.bind(this); - this.checkContact = this.checkContact.bind(this); - } - - checkContact(user) { - if (!Auth || typeof Auth.verifiedContact !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - Auth.verifiedContact(user) - .then(data => { - if (!JS.isEmpty(data.verified)) { - this.changeState('signedIn', user); - } else { - user = Object.assign(user, data); - this.changeState('verifyContact', user); - } - }); - } - - change() { - const user = this.props.authData; - const { password } = this.inputs; - const { requiredAttributes } = user.challengeParam; - const attrs = objectWithProperties(this.inputs, requiredAttributes); - - if (!Auth || typeof Auth.completeNewPassword !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - Auth.completeNewPassword(user, password, attrs) - .then(user => { - logger.debug('complete new password', user); - if (user.challengeName === 'SMS_MFA') { - this.changeState('confirmSignIn', user); - } else if (user.challengeName === 'MFA_SETUP') { - logger.debug('TOTP setup', user.challengeParam); - this.changeState('TOTPSetup', user); - } else { - this.checkContact(user); - } - }) - .catch(err => this.error(err)); - } - - showComponent(theme) { - const { hide } = this.props; - if (hide && hide.includes(RequireNewPassword)) { return null; } - - const user = this.props.authData; - const { requiredAttributes } = user.challengeParam; - - return ( - - {I18n.get('Change Password')} - - - - {requiredAttributes - .map(attribute => ( - - ))} - - - - - - - - this.changeState('signIn')} - data-test={auth.requireNewPassword.backToSignInLink} - > - {I18n.get('Back to Sign In')} - - - - - ) - } + constructor(props) { + super(props); + + this._validAuthStates = ['requireNewPassword']; + this.change = this.change.bind(this); + this.checkContact = this.checkContact.bind(this); + } + + checkContact(user) { + if (!Auth || typeof Auth.verifiedContact !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + Auth.verifiedContact(user).then(data => { + if (!JS.isEmpty(data.verified)) { + this.changeState('signedIn', user); + } else { + user = Object.assign(user, data); + this.changeState('verifyContact', user); + } + }); + } + + change() { + const user = this.props.authData; + const { password } = this.inputs; + const { requiredAttributes } = user.challengeParam; + const attrs = objectWithProperties(this.inputs, requiredAttributes); + + if (!Auth || typeof Auth.completeNewPassword !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + Auth.completeNewPassword(user, password, attrs) + .then(user => { + logger.debug('complete new password', user); + if (user.challengeName === 'SMS_MFA') { + this.changeState('confirmSignIn', user); + } else if (user.challengeName === 'MFA_SETUP') { + logger.debug('TOTP setup', user.challengeParam); + this.changeState('TOTPSetup', user); + } else { + this.checkContact(user); + } + }) + .catch(err => this.error(err)); + } + + showComponent(theme) { + const { hide } = this.props; + if (hide && hide.includes(RequireNewPassword)) { + return null; + } + + const user = this.props.authData; + const { requiredAttributes } = user.challengeParam; + + return ( + + + {I18n.get('Change Password')} + + + + + {requiredAttributes.map(attribute => ( + + ))} + + + + + + + this.changeState('signIn')} + data-test={auth.requireNewPassword.backToSignInLink} + > + {I18n.get('Back to Sign In')} + + + + + ); + } } function convertToPlaceholder(str) { - return str.split('_').map(part => part.charAt(0).toUpperCase() + part.substr(1).toLowerCase()).join(' ') + return str + .split('_') + .map(part => part.charAt(0).toUpperCase() + part.substr(1).toLowerCase()) + .join(' '); } function objectWithProperties(obj, keys) { - const target = {}; - for (const key in obj) { - if (keys.indexOf(key) === -1) { - continue; - } - if (!Object.prototype.hasOwnProperty.call(obj, key)) { - continue; - } - target[key] = obj[key]; - } - return target; + const target = {}; + for (const key in obj) { + if (keys.indexOf(key) === -1) { + continue; + } + if (!Object.prototype.hasOwnProperty.call(obj, key)) { + continue; + } + target[key] = obj[key]; + } + return target; } diff --git a/packages/aws-amplify-react/src/Auth/SignIn.jsx b/packages/aws-amplify-react/src/Auth/SignIn.jsx index 3393cefc900..c00b3770fa9 100644 --- a/packages/aws-amplify-react/src/Auth/SignIn.jsx +++ b/packages/aws-amplify-react/src/Auth/SignIn.jsx @@ -21,18 +21,18 @@ import SignUp from './SignUp'; import ForgotPassword from './ForgotPassword'; import { - FormSection, - FormField, - SectionHeader, - SectionBody, - SectionFooter, - Button, - Link, - Hint, - Input, - InputLabel, - SectionFooterPrimaryContent, - SectionFooterSecondaryContent + FormSection, + FormField, + SectionHeader, + SectionBody, + SectionFooter, + Button, + Link, + Hint, + Input, + InputLabel, + SectionFooterPrimaryContent, + SectionFooterSecondaryContent, } from '../Amplify-UI/Amplify-UI-Components-React'; import { auth } from '../Amplify-UI/data-test-attributes'; @@ -40,145 +40,171 @@ import { auth } from '../Amplify-UI/data-test-attributes'; const logger = new Logger('SignIn'); export default class SignIn extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.checkContact = this.checkContact.bind(this); - this.signIn = this.signIn.bind(this); + this.checkContact = this.checkContact.bind(this); + this.signIn = this.signIn.bind(this); - this._validAuthStates = ['signIn', 'signedOut', 'signedUp']; - this.state = {}; - } + this._validAuthStates = ['signIn', 'signedOut', 'signedUp']; + this.state = {}; + } - checkContact(user) { - if (!Auth || typeof Auth.verifiedContact !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - Auth.verifiedContact(user) - .then(data => { - if (!JS.isEmpty(data.verified)) { - this.changeState('signedIn', user); - } else { - user = Object.assign(user, data); - this.changeState('verifyContact', user); - } - }); - } + checkContact(user) { + if (!Auth || typeof Auth.verifiedContact !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + Auth.verifiedContact(user).then(data => { + if (!JS.isEmpty(data.verified)) { + this.changeState('signedIn', user); + } else { + user = Object.assign(user, data); + this.changeState('verifyContact', user); + } + }); + } - async signIn(event) { - // avoid submitting the form - if (event) { - event.preventDefault(); - } + async signIn(event) { + // avoid submitting the form + if (event) { + event.preventDefault(); + } - const username = this.getUsernameFromInput() || ''; - const password = this.inputs.password; + const username = this.getUsernameFromInput() || ''; + const password = this.inputs.password; - if (!Auth || typeof Auth.signIn !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - this.setState({loading: true}); - try { - const user = await Auth.signIn(username, password); - logger.debug(user); - if (user.challengeName === 'SMS_MFA' || user.challengeName === 'SOFTWARE_TOKEN_MFA') { - logger.debug('confirm user with ' + user.challengeName); - this.changeState('confirmSignIn', user); - } else if (user.challengeName === 'NEW_PASSWORD_REQUIRED') { - logger.debug('require new password', user.challengeParam); - this.changeState('requireNewPassword', user); - } else if (user.challengeName === 'MFA_SETUP') { - logger.debug('TOTP setup', user.challengeParam); - this.changeState('TOTPSetup', user); - } else if (user.challengeName === 'CUSTOM_CHALLENGE' && - user.challengeParam && - user.challengeParam.trigger === 'true' - ) { - logger.debug('custom challenge', user.challengeParam); - this.changeState('customConfirmSignIn', user); - } else { - this.checkContact(user); - } - } catch (err) { - if (err.code === 'UserNotConfirmedException') { - logger.debug('the user is not confirmed'); - this.changeState('confirmSignUp', {username}); - } else if (err.code === 'PasswordResetRequiredException') { - logger.debug('the user requires a new password'); - this.changeState('forgotPassword', {username}); - } else { - this.error(err); - } - } finally { - this.setState({loading: false}) - } - } - - showComponent(theme) { - const { authState, hide = [], federated, onStateChange, onAuthEvent, override=[] } = this.props; - if (hide && hide.includes(SignIn)) { return null; } - const hideSignUp = !override.includes('SignUp') && hide.some(component => component === SignUp); - const hideForgotPassword = !override.includes('ForgotPassword') && hide.some(component => component === ForgotPassword); - return ( - - {I18n.get('Sign in to your account')} - -
- - {this.renderUsernameField(theme)} - - {I18n.get('Password')} * - - { - !hideForgotPassword && - {I18n.get('Forget your password? ')} - this.changeState('forgotPassword')} data-test={auth.signIn.forgotPasswordLink}> - {I18n.get('Reset password')} - - - } - - - - - - - { - !hideSignUp && - {I18n.get('No account? ')} - this.changeState('signUp')} - data-test={auth.signIn.createAccountLink} - > - {I18n.get('Create account')} - - - } - -
-
- ); - } + if (!Auth || typeof Auth.signIn !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + this.setState({ loading: true }); + try { + const user = await Auth.signIn(username, password); + logger.debug(user); + if ( + user.challengeName === 'SMS_MFA' || + user.challengeName === 'SOFTWARE_TOKEN_MFA' + ) { + logger.debug('confirm user with ' + user.challengeName); + this.changeState('confirmSignIn', user); + } else if (user.challengeName === 'NEW_PASSWORD_REQUIRED') { + logger.debug('require new password', user.challengeParam); + this.changeState('requireNewPassword', user); + } else if (user.challengeName === 'MFA_SETUP') { + logger.debug('TOTP setup', user.challengeParam); + this.changeState('TOTPSetup', user); + } else if ( + user.challengeName === 'CUSTOM_CHALLENGE' && + user.challengeParam && + user.challengeParam.trigger === 'true' + ) { + logger.debug('custom challenge', user.challengeParam); + this.changeState('customConfirmSignIn', user); + } else { + this.checkContact(user); + } + } catch (err) { + if (err.code === 'UserNotConfirmedException') { + logger.debug('the user is not confirmed'); + this.changeState('confirmSignUp', { username }); + } else if (err.code === 'PasswordResetRequiredException') { + logger.debug('the user requires a new password'); + this.changeState('forgotPassword', { username }); + } else { + this.error(err); + } + } finally { + this.setState({ loading: false }); + } + } + + showComponent(theme) { + const { + authState, + hide = [], + federated, + onStateChange, + onAuthEvent, + override = [], + } = this.props; + if (hide && hide.includes(SignIn)) { + return null; + } + const hideSignUp = + !override.includes('SignUp') && + hide.some(component => component === SignUp); + const hideForgotPassword = + !override.includes('ForgotPassword') && + hide.some(component => component === ForgotPassword); + return ( + + + {I18n.get('Sign in to your account')} + + +
+ + {this.renderUsernameField(theme)} + + {I18n.get('Password')} * + + {!hideForgotPassword && ( + + {I18n.get('Forget your password? ')} + this.changeState('forgotPassword')} + data-test={auth.signIn.forgotPasswordLink} + > + {I18n.get('Reset password')} + + + )} + + + + + + + {!hideSignUp && ( + + {I18n.get('No account? ')} + this.changeState('signUp')} + data-test={auth.signIn.createAccountLink} + > + {I18n.get('Create account')} + + + )} + +
+
+ ); + } } diff --git a/packages/aws-amplify-react/src/Auth/SignOut.jsx b/packages/aws-amplify-react/src/Auth/SignOut.jsx index 1c2c953dc01..3df209fa446 100644 --- a/packages/aws-amplify-react/src/Auth/SignOut.jsx +++ b/packages/aws-amplify-react/src/Auth/SignOut.jsx @@ -26,123 +26,148 @@ import { auth } from '../Amplify-UI/data-test-attributes'; const logger = new Logger('SignOut'); export default class SignOut extends AuthPiece { - constructor(props) { - super(props); - - this.signOut = this.signOut.bind(this); - this.onHubCapsule = this.onHubCapsule.bind(this) - Hub.listen('auth', this.onHubCapsule) - this.state = {}; - } - - componentDidMount() { - this._isMounted = true; - this.findState(); - } - - componentWillUnmount() { - this._isMounted = false; - } - - findState(){ - if (!this.props.authState && !this.props.authData) { - Auth.currentAuthenticatedUser() - .then(user => { - this.setState({ - authState: 'signedIn', - authData: user, - stateFromStorage: true - }) - }) - .catch(err => logger.error(err)); - } else if (this.props.stateFromStorage) { - this.setState({ - stateFromStorage: true - }) - } - } - - onHubCapsule(capsule) { - if (this._isMounted) { - const { channel, payload, source } = capsule; - if (channel === 'auth' && payload.event === 'signIn') { - this.setState({ - authState: 'signedIn', - authData: payload.data - }) - } else if (channel === 'auth' && payload.event === 'signOut' && (!this.props.authState)) { - this.setState({ - authState: 'signIn' - }) - } - - if (channel === 'auth' && payload.event === 'signIn' && (!this.props.authState)) { - this.setState({stateFromStorage: true}) - } - } - } - - signOut() { - let payload = {}; - try { - payload = JSON.parse(localStorage.getItem(Constants.AUTH_SOURCE_KEY)) || {}; - localStorage.removeItem(Constants.AUTH_SOURCE_KEY); - } catch (e) { - logger.debug(`Failed to parse the info from ${Constants.AUTH_SOURCE_KEY} from localStorage with ${e}`); - } - logger.debug('sign out from the source', payload); - const { googleSignOut, facebookSignOut, amazonSignOut, auth0SignOut } = this.props; - switch (payload.provider) { - case Constants.GOOGLE: - if (googleSignOut) googleSignOut(); - else logger.debug('No Google signout method provided'); - break; - case Constants.FACEBOOK: - if (facebookSignOut) facebookSignOut(); - else logger.debug('No Facebook signout method provided'); - break; - case Constants.AMAZON: - if (amazonSignOut) amazonSignOut(); - else logger.debug('No Amazon signout method provided'); - break; - case Constants.AUTH0: - if (auth0SignOut) auth0SignOut(payload.opts); - else logger.debug('No Auth0 signout method provided'); - break; - default: - break; - } - - if (!Auth || typeof Auth.signOut !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - Auth.signOut() - .then(() => { - if (!this.state.stateFromStorage) { - this.changeState('signedOut'); - } - }) - .catch(err => { logger.debug(err); this.error(err); }); - } - - render() { - const { hide } = this.props; - if (hide && hide.includes(SignOut)) { return null; } - - const authState = this.props.authState || this.state.authState; - const signedIn = (authState === 'signedIn'); - - const theme = this.props.theme || AmplifyTheme; - if (!signedIn) { return null; } - - return ( - - {I18n.get('Sign Out')} - - ); - } + constructor(props) { + super(props); + + this.signOut = this.signOut.bind(this); + this.onHubCapsule = this.onHubCapsule.bind(this); + Hub.listen('auth', this.onHubCapsule); + this.state = {}; + } + + componentDidMount() { + this._isMounted = true; + this.findState(); + } + + componentWillUnmount() { + this._isMounted = false; + } + + findState() { + if (!this.props.authState && !this.props.authData) { + Auth.currentAuthenticatedUser() + .then(user => { + this.setState({ + authState: 'signedIn', + authData: user, + stateFromStorage: true, + }); + }) + .catch(err => logger.error(err)); + } else if (this.props.stateFromStorage) { + this.setState({ + stateFromStorage: true, + }); + } + } + + onHubCapsule(capsule) { + if (this._isMounted) { + const { channel, payload, source } = capsule; + if (channel === 'auth' && payload.event === 'signIn') { + this.setState({ + authState: 'signedIn', + authData: payload.data, + }); + } else if ( + channel === 'auth' && + payload.event === 'signOut' && + !this.props.authState + ) { + this.setState({ + authState: 'signIn', + }); + } + + if ( + channel === 'auth' && + payload.event === 'signIn' && + !this.props.authState + ) { + this.setState({ stateFromStorage: true }); + } + } + } + + signOut() { + let payload = {}; + try { + payload = + JSON.parse(localStorage.getItem(Constants.AUTH_SOURCE_KEY)) || {}; + localStorage.removeItem(Constants.AUTH_SOURCE_KEY); + } catch (e) { + logger.debug( + `Failed to parse the info from ${Constants.AUTH_SOURCE_KEY} from localStorage with ${e}` + ); + } + logger.debug('sign out from the source', payload); + const { + googleSignOut, + facebookSignOut, + amazonSignOut, + auth0SignOut, + } = this.props; + switch (payload.provider) { + case Constants.GOOGLE: + if (googleSignOut) googleSignOut(); + else logger.debug('No Google signout method provided'); + break; + case Constants.FACEBOOK: + if (facebookSignOut) facebookSignOut(); + else logger.debug('No Facebook signout method provided'); + break; + case Constants.AMAZON: + if (amazonSignOut) amazonSignOut(); + else logger.debug('No Amazon signout method provided'); + break; + case Constants.AUTH0: + if (auth0SignOut) auth0SignOut(payload.opts); + else logger.debug('No Auth0 signout method provided'); + break; + default: + break; + } + + if (!Auth || typeof Auth.signOut !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + Auth.signOut() + .then(() => { + if (!this.state.stateFromStorage) { + this.changeState('signedOut'); + } + }) + .catch(err => { + logger.debug(err); + this.error(err); + }); + } + + render() { + const { hide } = this.props; + if (hide && hide.includes(SignOut)) { + return null; + } + + const authState = this.props.authState || this.state.authState; + const signedIn = authState === 'signedIn'; + + const theme = this.props.theme || AmplifyTheme; + if (!signedIn) { + return null; + } + + return ( + + {I18n.get('Sign Out')} + + ); + } } diff --git a/packages/aws-amplify-react/src/Auth/SignUp.jsx b/packages/aws-amplify-react/src/Auth/SignUp.jsx index ca565a9df2d..d6d39d67da9 100644 --- a/packages/aws-amplify-react/src/Auth/SignUp.jsx +++ b/packages/aws-amplify-react/src/Auth/SignUp.jsx @@ -18,279 +18,318 @@ import Auth from '@aws-amplify/auth'; import AuthPiece from './AuthPiece'; import { - FormSection, - SectionHeader, - SectionBody, - SectionFooter, - FormField, - Input, - InputLabel, - SelectInput, - Button, - Link, - SectionFooterPrimaryContent, - SectionFooterSecondaryContent, + FormSection, + SectionHeader, + SectionBody, + SectionFooter, + FormField, + Input, + InputLabel, + SelectInput, + Button, + Link, + SectionFooterPrimaryContent, + SectionFooterSecondaryContent, } from '../Amplify-UI/Amplify-UI-Components-React'; import { auth } from '../Amplify-UI/data-test-attributes'; import countryDialCodes from './common/country-dial-codes.js'; -import signUpWithUsernameFields, { - signUpWithEmailFields, - signUpWithPhoneNumberFields - } from './common/default-sign-up-fields' +import signUpWithUsernameFields, { + signUpWithEmailFields, + signUpWithPhoneNumberFields, +} from './common/default-sign-up-fields'; import { UsernameAttributes } from './common/types'; import { valid } from 'semver'; import { PhoneField } from './PhoneField'; const logger = new Logger('SignUp'); - export default class SignUp extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this._validAuthStates = ['signUp']; - this.signUp = this.signUp.bind(this); - this.sortFields = this.sortFields.bind(this); - this.getDefaultDialCode = this.getDefaultDialCode.bind(this); - this.checkCustomSignUpFields = this.checkCustomSignUpFields.bind(this); - this.needPrefix = this.needPrefix.bind(this); - this.header = (this.props && - this.props.signUpConfig && - this.props.signUpConfig.header) ? this.props.signUpConfig.header : 'Create a new account'; - - const { usernameAttributes=UsernameAttributes.USERNAME } = this.props || {}; - if (usernameAttributes === UsernameAttributes.EMAIL) { - this.defaultSignUpFields = signUpWithEmailFields; - } else if (usernameAttributes === UsernameAttributes.PHONE_NUMBER) { - this.defaultSignUpFields = signUpWithPhoneNumberFields; - } else { - this.defaultSignUpFields = signUpWithUsernameFields; - } - } + this._validAuthStates = ['signUp']; + this.signUp = this.signUp.bind(this); + this.sortFields = this.sortFields.bind(this); + this.getDefaultDialCode = this.getDefaultDialCode.bind(this); + this.checkCustomSignUpFields = this.checkCustomSignUpFields.bind(this); + this.needPrefix = this.needPrefix.bind(this); + this.header = + this.props && this.props.signUpConfig && this.props.signUpConfig.header + ? this.props.signUpConfig.header + : 'Create a new account'; - validate() { - const invalids = []; - this.signUpFields.map((el) => { - if (el.key !== 'phone_number') { - if (el.required && !this.inputs[el.key]) { - el.invalid = true; - invalids.push(el.label); - } else { - el.invalid = false; - } - } else { - if (el.required && (!this.phone_number)) { - el.invalid = true; - invalids.push(el.label); - } else { - el.invalid = false; - } - } - }); - return invalids; - } + const { usernameAttributes = UsernameAttributes.USERNAME } = + this.props || {}; + if (usernameAttributes === UsernameAttributes.EMAIL) { + this.defaultSignUpFields = signUpWithEmailFields; + } else if (usernameAttributes === UsernameAttributes.PHONE_NUMBER) { + this.defaultSignUpFields = signUpWithPhoneNumberFields; + } else { + this.defaultSignUpFields = signUpWithUsernameFields; + } + } - sortFields() { + validate() { + const invalids = []; + this.signUpFields.map(el => { + if (el.key !== 'phone_number') { + if (el.required && !this.inputs[el.key]) { + el.invalid = true; + invalids.push(el.label); + } else { + el.invalid = false; + } + } else { + if (el.required && !this.phone_number) { + el.invalid = true; + invalids.push(el.label); + } else { + el.invalid = false; + } + } + }); + return invalids; + } - if (this.props.signUpConfig && this.props.signUpConfig.hiddenDefaults && this.props.signUpConfig.hiddenDefaults.length > 0){ - this.defaultSignUpFields = this.defaultSignUpFields.filter((d) => { - return !this.props.signUpConfig.hiddenDefaults.includes(d.key); - }); - } + sortFields() { + if ( + this.props.signUpConfig && + this.props.signUpConfig.hiddenDefaults && + this.props.signUpConfig.hiddenDefaults.length > 0 + ) { + this.defaultSignUpFields = this.defaultSignUpFields.filter(d => { + return !this.props.signUpConfig.hiddenDefaults.includes(d.key); + }); + } - if (this.checkCustomSignUpFields()) { + if (this.checkCustomSignUpFields()) { + if ( + !this.props.signUpConfig || + !this.props.signUpConfig.hideAllDefaults + ) { + // see if fields passed to component should override defaults + this.defaultSignUpFields.forEach((f, i) => { + const matchKey = this.signUpFields.findIndex(d => { + return d.key === f.key; + }); + if (matchKey === -1) { + this.signUpFields.push(f); + } + }); + } - if (!this.props.signUpConfig || !this.props.signUpConfig.hideAllDefaults) { - // see if fields passed to component should override defaults - this.defaultSignUpFields.forEach((f, i) => { - const matchKey = this.signUpFields.findIndex((d) => { - return d.key === f.key; - }); - if (matchKey === -1) { - this.signUpFields.push(f); - } - }); - } - - /* + /* sort fields based on following rules: 1. Fields with displayOrder are sorted before those without displayOrder 2. Fields with conflicting displayOrder are sorted alphabetically by key 3. Fields without displayOrder are sorted alphabetically by key */ - this.signUpFields.sort((a, b) => { - if (a.displayOrder && b.displayOrder) { - if (a.displayOrder < b.displayOrder) { - return -1; - } else if (a.displayOrder > b.displayOrder) { - return 1; - } else { - if (a.key < b.key) { - return -1; - } else { - return 1; - } - } - } else if (!a.displayOrder && b.displayOrder) { - return 1; - } else if (a.displayOrder && !b.displayOrder) { - return -1; - } else if (!a.displayOrder && !b.displayOrder) { - if (a.key < b.key) { - return -1; - } else { - return 1; - } - } - }); - } else { - this.signUpFields = this.defaultSignUpFields; - } - } + this.signUpFields.sort((a, b) => { + if (a.displayOrder && b.displayOrder) { + if (a.displayOrder < b.displayOrder) { + return -1; + } else if (a.displayOrder > b.displayOrder) { + return 1; + } else { + if (a.key < b.key) { + return -1; + } else { + return 1; + } + } + } else if (!a.displayOrder && b.displayOrder) { + return 1; + } else if (a.displayOrder && !b.displayOrder) { + return -1; + } else if (!a.displayOrder && !b.displayOrder) { + if (a.key < b.key) { + return -1; + } else { + return 1; + } + } + }); + } else { + this.signUpFields = this.defaultSignUpFields; + } + } - needPrefix(key) { - const field = this.signUpFields.find(e => e.key === key); - if (key.indexOf('custom:') !== 0) { - return field.custom ; - } else if (key.indexOf('custom:') === 0 && field.custom === false) { - logger.warn('Custom prefix prepended to key but custom field flag is set to false; retaining manually entered prefix'); - - } - return null; - } + needPrefix(key) { + const field = this.signUpFields.find(e => e.key === key); + if (key.indexOf('custom:') !== 0) { + return field.custom; + } else if (key.indexOf('custom:') === 0 && field.custom === false) { + logger.warn( + 'Custom prefix prepended to key but custom field flag is set to false; retaining manually entered prefix' + ); + } + return null; + } - getDefaultDialCode() { - return this.props.signUpConfig && - this.props.signUpConfig.defaultCountryCode && - countryDialCodes.indexOf(`+${this.props.signUpConfig.defaultCountryCode}`) !== '-1' ? - `+${this.props.signUpConfig.defaultCountryCode}` : - "+1" - } + getDefaultDialCode() { + return this.props.signUpConfig && + this.props.signUpConfig.defaultCountryCode && + countryDialCodes.indexOf( + `+${this.props.signUpConfig.defaultCountryCode}` + ) !== '-1' + ? `+${this.props.signUpConfig.defaultCountryCode}` + : '+1'; + } - checkCustomSignUpFields() { - return this.props.signUpConfig && - this.props.signUpConfig.signUpFields && - this.props.signUpConfig.signUpFields.length > 0 - } + checkCustomSignUpFields() { + return ( + this.props.signUpConfig && + this.props.signUpConfig.signUpFields && + this.props.signUpConfig.signUpFields.length > 0 + ); + } - signUp() { - if (!this.inputs.dial_code) { - this.inputs.dial_code = this.getDefaultDialCode(); - } - const validation = this.validate(); - if (validation && validation.length > 0) { - return this.error(`The following fields need to be filled out: ${validation.join(', ')}`); - } - if (!Auth || typeof Auth.signUp !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } + signUp() { + if (!this.inputs.dial_code) { + this.inputs.dial_code = this.getDefaultDialCode(); + } + const validation = this.validate(); + if (validation && validation.length > 0) { + return this.error( + `The following fields need to be filled out: ${validation.join(', ')}` + ); + } + if (!Auth || typeof Auth.signUp !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } - const signup_info = { - username: this.inputs.username, - password: this.inputs.password, - attributes: {} - }; + const signup_info = { + username: this.inputs.username, + password: this.inputs.password, + attributes: {}, + }; - const inputKeys = Object.keys(this.inputs); - const inputVals = Object.values(this.inputs); + const inputKeys = Object.keys(this.inputs); + const inputVals = Object.values(this.inputs); - inputKeys.forEach((key, index) => { - if (!['username', 'password', 'checkedValue', 'dial_code'].includes(key)) { - if (key !== 'phone_line_number' && key !== 'dial_code' && key !== 'error') { - const newKey = `${this.needPrefix(key) ? 'custom:' : ''}${key}`; - signup_info.attributes[newKey] = inputVals[index]; - } - } - }); + inputKeys.forEach((key, index) => { + if ( + !['username', 'password', 'checkedValue', 'dial_code'].includes(key) + ) { + if ( + key !== 'phone_line_number' && + key !== 'dial_code' && + key !== 'error' + ) { + const newKey = `${this.needPrefix(key) ? 'custom:' : ''}${key}`; + signup_info.attributes[newKey] = inputVals[index]; + } + } + }); - if (this.phone_number) signup_info.attributes['phone_number'] = this.phone_number; - - let labelCheck = false; - this.signUpFields.forEach(field => { - if (field.label === this.getUsernameLabel()) { - logger.debug(`Changing the username to the value of ${field.label}`); - signup_info.username = signup_info.attributes[field.key] || signup_info.username; - labelCheck = true; - } - }); - if (!labelCheck && !signup_info.username) { - // if the customer customized the username field in the sign up form - // He needs to either set the key of that field to 'username' - // Or make the label of the field the same as the 'usernameAttributes' - throw new Error(`Couldn't find the label: ${this.getUsernameLabel()}, in sign up fields according to usernameAttributes!`); - } - Auth.signUp(signup_info).then((data) => { - this.changeState('confirmSignUp', data.user.username) - }) - .catch(err => this.error(err)); - } + if (this.phone_number) + signup_info.attributes['phone_number'] = this.phone_number; - showComponent(theme) { - const { hide } = this.props; - if (hide && hide.includes(SignUp)) { return null; } - if (this.checkCustomSignUpFields()) { - this.signUpFields = this.props.signUpConfig.signUpFields; - } - this.sortFields(); - return ( - - {I18n.get(this.header)} - - { - this.signUpFields.map((field) => { - return field.key !== 'phone_number' ? ( - - { - field.required ? - {I18n.get(field.label)} * : - {I18n.get(field.label)} - } - { - return f.key === field.key - }) === 0 ? true : false - } - placeholder={I18n.get(field.placeholder)} - theme={theme} - type={field.type} - name={field.key} - key={field.key} - onChange={this.handleInputChange} - data-test={auth.signUp.nonPhoneNumberInput} - /> - - ) : ( - - ) - }) - } - - - - - - - {I18n.get('Have an account? ')} - this.changeState('signIn')} data-test={auth.signUp.signInLink}> - {I18n.get('Sign in')} - - - - - ); - } + let labelCheck = false; + this.signUpFields.forEach(field => { + if (field.label === this.getUsernameLabel()) { + logger.debug(`Changing the username to the value of ${field.label}`); + signup_info.username = + signup_info.attributes[field.key] || signup_info.username; + labelCheck = true; + } + }); + if (!labelCheck && !signup_info.username) { + // if the customer customized the username field in the sign up form + // He needs to either set the key of that field to 'username' + // Or make the label of the field the same as the 'usernameAttributes' + throw new Error( + `Couldn't find the label: ${this.getUsernameLabel()}, in sign up fields according to usernameAttributes!` + ); + } + Auth.signUp(signup_info) + .then(data => { + this.changeState('confirmSignUp', data.user.username); + }) + .catch(err => this.error(err)); + } + showComponent(theme) { + const { hide } = this.props; + if (hide && hide.includes(SignUp)) { + return null; + } + if (this.checkCustomSignUpFields()) { + this.signUpFields = this.props.signUpConfig.signUpFields; + } + this.sortFields(); + return ( + + + {I18n.get(this.header)} + + + {this.signUpFields.map(field => { + return field.key !== 'phone_number' ? ( + + {field.required ? ( + + {I18n.get(field.label)} * + + ) : ( + {I18n.get(field.label)} + )} + { + return f.key === field.key; + }) === 0 + ? true + : false + } + placeholder={I18n.get(field.placeholder)} + theme={theme} + type={field.type} + name={field.key} + key={field.key} + onChange={this.handleInputChange} + data-test={auth.signUp.nonPhoneNumberInput} + /> + + ) : ( + + ); + })} + + + + + + + {I18n.get('Have an account? ')} + this.changeState('signIn')} + data-test={auth.signUp.signInLink} + > + {I18n.get('Sign in')} + + + + + ); + } } diff --git a/packages/aws-amplify-react/src/Auth/TOTPSetup.jsx b/packages/aws-amplify-react/src/Auth/TOTPSetup.jsx index f11a4c08c5f..bc097bc8324 100644 --- a/packages/aws-amplify-react/src/Auth/TOTPSetup.jsx +++ b/packages/aws-amplify-react/src/Auth/TOTPSetup.jsx @@ -22,45 +22,52 @@ import { auth } from '../Amplify-UI/data-test-attributes'; const logger = new Logger('TOTPSetup'); export default class TOTPSetup extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this._validAuthStates = ['TOTPSetup']; - this.onTOTPEvent = this.onTOTPEvent.bind(this); - this.checkContact = this.checkContact.bind(this); - } + this._validAuthStates = ['TOTPSetup']; + this.onTOTPEvent = this.onTOTPEvent.bind(this); + this.checkContact = this.checkContact.bind(this); + } - checkContact(user) { - if (!Auth || typeof Auth.verifiedContact !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - Auth.verifiedContact(user) - .then(data => { - if (!JS.isEmpty(data.verified)) { - this.changeState('signedIn', user); - } else { - const newUser = Object.assign(user, data); - this.changeState('verifyContact', newUser); - } - }); - } + checkContact(user) { + if (!Auth || typeof Auth.verifiedContact !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + Auth.verifiedContact(user).then(data => { + if (!JS.isEmpty(data.verified)) { + this.changeState('signedIn', user); + } else { + const newUser = Object.assign(user, data); + this.changeState('verifyContact', newUser); + } + }); + } - onTOTPEvent(event, data, user) { - logger.debug('on totp event', event, data); - // const user = this.props.authData; - if (event === 'Setup TOTP') { - if (data === 'SUCCESS') { - this.checkContact(user); - } - } - } + onTOTPEvent(event, data, user) { + logger.debug('on totp event', event, data); + // const user = this.props.authData; + if (event === 'Setup TOTP') { + if (data === 'SUCCESS') { + this.checkContact(user); + } + } + } - showComponent(theme) { - const { hide } = this.props; - if (hide && hide.includes(TOTPSetup)) { return null; } + showComponent(theme) { + const { hide } = this.props; + if (hide && hide.includes(TOTPSetup)) { + return null; + } - return ( - - ); - } + return ( + + ); + } } diff --git a/packages/aws-amplify-react/src/Auth/VerifyContact.jsx b/packages/aws-amplify-react/src/Auth/VerifyContact.jsx index f2aeb6583a4..36c2676c486 100644 --- a/packages/aws-amplify-react/src/Auth/VerifyContact.jsx +++ b/packages/aws-amplify-react/src/Auth/VerifyContact.jsx @@ -18,16 +18,16 @@ import Auth from '@aws-amplify/auth'; import AuthPiece from './AuthPiece'; import AmplifyTheme from '../AmplifyTheme'; import { - FormSection, - SectionHeader, - SectionBody, - SectionFooter, - Input, - RadioRow, - Button, - Link, - SectionFooterPrimaryContent, - SectionFooterSecondaryContent + FormSection, + SectionHeader, + SectionBody, + SectionFooter, + Input, + RadioRow, + Button, + Link, + SectionFooterPrimaryContent, + SectionFooterSecondaryContent, } from '../Amplify-UI/Amplify-UI-Components-React'; import { auth } from '../Amplify-UI/data-test-attributes'; @@ -35,129 +35,157 @@ import { auth } from '../Amplify-UI/data-test-attributes'; const logger = new Logger('VerifyContact'); export default class VerifyContact extends AuthPiece { - constructor(props) { - super(props); + constructor(props) { + super(props); - this._validAuthStates = ['verifyContact']; - this.verify = this.verify.bind(this); - this.submit = this.submit.bind(this); + this._validAuthStates = ['verifyContact']; + this.verify = this.verify.bind(this); + this.submit = this.submit.bind(this); - this.state = { verifyAttr: null }; - } + this.state = { verifyAttr: null }; + } - verify() { - const { contact, checkedValue } = this.inputs; - if (!contact) { - this.error('Neither Email nor Phone Number selected'); - return; - } + verify() { + const { contact, checkedValue } = this.inputs; + if (!contact) { + this.error('Neither Email nor Phone Number selected'); + return; + } - if (!Auth || typeof Auth.verifyCurrentUserAttribute !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } + if (!Auth || typeof Auth.verifyCurrentUserAttribute !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } - Auth.verifyCurrentUserAttribute(checkedValue) - .then(data => { - logger.debug(data); - this.setState({ verifyAttr: checkedValue }); - }) - .catch(err => this.error(err)); - } + Auth.verifyCurrentUserAttribute(checkedValue) + .then(data => { + logger.debug(data); + this.setState({ verifyAttr: checkedValue }); + }) + .catch(err => this.error(err)); + } - submit() { - const attr = this.state.verifyAttr; - const { code } = this.inputs; - if (!Auth || typeof Auth.verifyCurrentUserAttributeSubmit !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - Auth.verifyCurrentUserAttributeSubmit(attr, code) - .then(data => { - logger.debug(data); - this.changeState('signedIn', this.props.authData); - this.setState({ verifyAttr: null }); - }) - .catch(err => this.error(err)); - } + submit() { + const attr = this.state.verifyAttr; + const { code } = this.inputs; + if (!Auth || typeof Auth.verifyCurrentUserAttributeSubmit !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + Auth.verifyCurrentUserAttributeSubmit(attr, code) + .then(data => { + logger.debug(data); + this.changeState('signedIn', this.props.authData); + this.setState({ verifyAttr: null }); + }) + .catch(err => this.error(err)); + } - verifyView() { - const user = this.props.authData; - if (!user) { - logger.debug('no user for verify'); - return null; - } - const { unverified } = user; - if (!unverified) { - logger.debug('no unverified on user'); - return null; - } - const { email, phone_number } = unverified; - const theme = this.props.theme || AmplifyTheme; - return ( -
- { email? : null - } - { phone_number? : null - } -
- ); - } + verifyView() { + const user = this.props.authData; + if (!user) { + logger.debug('no user for verify'); + return null; + } + const { unverified } = user; + if (!unverified) { + logger.debug('no unverified on user'); + return null; + } + const { email, phone_number } = unverified; + const theme = this.props.theme || AmplifyTheme; + return ( +
+ {email ? ( + + ) : null} + {phone_number ? ( + + ) : null} +
+ ); + } - submitView() { - const theme = this.props.theme || AmplifyTheme; - return ( -
- -
- ); - } + submitView() { + const theme = this.props.theme || AmplifyTheme; + return ( +
+ +
+ ); + } - showComponent(theme) { - const { authData, hide } = this.props; - if (hide && hide.includes(VerifyContact)) { return null; } + showComponent(theme) { + const { authData, hide } = this.props; + if (hide && hide.includes(VerifyContact)) { + return null; + } - return ( - - - {I18n.get('Account recovery requires verified contact information')} - - - { this.state.verifyAttr ? this.submitView() : this.verifyView() } - - - - { this.state.verifyAttr ? - : - - } - - - this.changeState('signedIn', authData)} data-test={auth.verifyContact.skipLink}> - {I18n.get('Skip')} - - - - - ); - } + return ( + + + {I18n.get('Account recovery requires verified contact information')} + + + {this.state.verifyAttr ? this.submitView() : this.verifyView()} + + + + {this.state.verifyAttr ? ( + + ) : ( + + )} + + + this.changeState('signedIn', authData)} + data-test={auth.verifyContact.skipLink} + > + {I18n.get('Skip')} + + + + + ); + } } diff --git a/packages/aws-amplify-react/src/Auth/common/constants.js b/packages/aws-amplify-react/src/Auth/common/constants.js index d45fa150895..424fa8a841a 100644 --- a/packages/aws-amplify-react/src/Auth/common/constants.js +++ b/packages/aws-amplify-react/src/Auth/common/constants.js @@ -1,9 +1,9 @@ const constants = { - AUTH_SOURCE_KEY: 'amplify-react-auth-source', - AUTH0: 'auth0', - GOOGLE: 'google', - FACEBOOK: 'facebook', - AMAZON: 'amazon', - SIGNING_IN_WITH_HOSTEDUI_KEY: 'amplify-signin-with-hostedUI' + AUTH_SOURCE_KEY: 'amplify-react-auth-source', + AUTH0: 'auth0', + GOOGLE: 'google', + FACEBOOK: 'facebook', + AMAZON: 'amazon', + SIGNING_IN_WITH_HOSTEDUI_KEY: 'amplify-signin-with-hostedUI', }; -export default constants; +export default constants; diff --git a/packages/aws-amplify-react/src/Auth/common/country-dial-codes.js b/packages/aws-amplify-react/src/Auth/common/country-dial-codes.js index f887e04c70a..33e0c116d19 100644 --- a/packages/aws-amplify-react/src/Auth/common/country-dial-codes.js +++ b/packages/aws-amplify-react/src/Auth/common/country-dial-codes.js @@ -1,208 +1,208 @@ export default [ - "+1", - "+7", - "+20", - "+27", - "+30", - "+31", - "+32", - "+33", - "+34", - "+36", - "+39", - "+40", - "+41", - "+43", - "+44", - "+45", - "+46", - "+47", - "+48", - "+49", - "+51", - "+52", - "+53", - "+54", - "+55", - "+56", - "+57", - "+58", - "+60", - "+61", - "+62", - "+63", - "+64", - "+65", - "+66", - "+81", - "+82", - "+84", - "+86", - "+90", - "+91", - "+92", - "+93", - "+94", - "+95", - "+98", - "+212", - "+213", - "+216", - "+218", - "+220", - "+221", - "+222", - "+223", - "+224", - "+225", - "+226", - "+227", - "+228", - "+229", - "+230", - "+231", - "+232", - "+233", - "+234", - "+235", - "+236", - "+237", - "+238", - "+239", - "+240", - "+241", - "+242", - "+243", - "+244", - "+245", - "+246", - "+248", - "+249", - "+250", - "+251", - "+252", - "+253", - "+254", - "+255", - "+256", - "+257", - "+258", - "+260", - "+261", - "+262", - "+263", - "+264", - "+265", - "+266", - "+267", - "+268", - "+269", - "+290", - "+291", - "+297", - "+298", - "+299", - "+345", - "+350", - "+351", - "+352", - "+353", - "+354", - "+355", - "+356", - "+357", - "+358", - "+359", - "+370", - "+371", - "+372", - "+373", - "+374", - "+375", - "+376", - "+377", - "+378", - "+379", - "+380", - "+381", - "+382", - "+385", - "+386", - "+387", - "+389", - "+420", - "+421", - "+423", - "+500", - "+501", - "+502", - "+503", - "+504", - "+505", - "+506", - "+507", - "+508", - "+509", - "+537", - "+590", - "+591", - "+593", - "+594", - "+595", - "+596", - "+597", - "+598", - "+599", - "+670", - "+672", - "+673", - "+674", - "+675", - "+676", - "+677", - "+678", - "+679", - "+680", - "+681", - "+682", - "+683", - "+685", - "+686", - "+687", - "+688", - "+689", - "+690", - "+691", - "+692", - "+850", - "+852", - "+853", - "+855", - "+856", - "+872", - "+880", - "+886", - "+960", - "+961", - "+962", - "+963", - "+964", - "+965", - "+966", - "+967", - "+968", - "+970", - "+971", - "+972", - "+973", - "+974", - "+975", - "+976", - "+977", - "+992", - "+993", - "+994", - "+995", - "+996", - "+998", + '+1', + '+7', + '+20', + '+27', + '+30', + '+31', + '+32', + '+33', + '+34', + '+36', + '+39', + '+40', + '+41', + '+43', + '+44', + '+45', + '+46', + '+47', + '+48', + '+49', + '+51', + '+52', + '+53', + '+54', + '+55', + '+56', + '+57', + '+58', + '+60', + '+61', + '+62', + '+63', + '+64', + '+65', + '+66', + '+81', + '+82', + '+84', + '+86', + '+90', + '+91', + '+92', + '+93', + '+94', + '+95', + '+98', + '+212', + '+213', + '+216', + '+218', + '+220', + '+221', + '+222', + '+223', + '+224', + '+225', + '+226', + '+227', + '+228', + '+229', + '+230', + '+231', + '+232', + '+233', + '+234', + '+235', + '+236', + '+237', + '+238', + '+239', + '+240', + '+241', + '+242', + '+243', + '+244', + '+245', + '+246', + '+248', + '+249', + '+250', + '+251', + '+252', + '+253', + '+254', + '+255', + '+256', + '+257', + '+258', + '+260', + '+261', + '+262', + '+263', + '+264', + '+265', + '+266', + '+267', + '+268', + '+269', + '+290', + '+291', + '+297', + '+298', + '+299', + '+345', + '+350', + '+351', + '+352', + '+353', + '+354', + '+355', + '+356', + '+357', + '+358', + '+359', + '+370', + '+371', + '+372', + '+373', + '+374', + '+375', + '+376', + '+377', + '+378', + '+379', + '+380', + '+381', + '+382', + '+385', + '+386', + '+387', + '+389', + '+420', + '+421', + '+423', + '+500', + '+501', + '+502', + '+503', + '+504', + '+505', + '+506', + '+507', + '+508', + '+509', + '+537', + '+590', + '+591', + '+593', + '+594', + '+595', + '+596', + '+597', + '+598', + '+599', + '+670', + '+672', + '+673', + '+674', + '+675', + '+676', + '+677', + '+678', + '+679', + '+680', + '+681', + '+682', + '+683', + '+685', + '+686', + '+687', + '+688', + '+689', + '+690', + '+691', + '+692', + '+850', + '+852', + '+853', + '+855', + '+856', + '+872', + '+880', + '+886', + '+960', + '+961', + '+962', + '+963', + '+964', + '+965', + '+966', + '+967', + '+968', + '+970', + '+971', + '+972', + '+973', + '+974', + '+975', + '+976', + '+977', + '+992', + '+993', + '+994', + '+995', + '+996', + '+998', ]; diff --git a/packages/aws-amplify-react/src/Auth/common/default-sign-up-fields.js b/packages/aws-amplify-react/src/Auth/common/default-sign-up-fields.js index cf2364044d3..1aa92035c22 100644 --- a/packages/aws-amplify-react/src/Auth/common/default-sign-up-fields.js +++ b/packages/aws-amplify-react/src/Auth/common/default-sign-up-fields.js @@ -1,85 +1,84 @@ - export default [ - { - label: 'Username', - key: 'username', - required: true, - placeholder: 'Username', - displayOrder: 1, - }, - { - label: 'Password', - key: 'password', - required: true, - placeholder: 'Password', - type: 'password', - displayOrder: 2, - }, - { - label: 'Email', - key: 'email', - required: true, - placeholder: 'Email', - type: 'email', - displayOrder: 3 - }, - { - label: 'Phone Number', - key: 'phone_number', - placeholder: 'Phone Number', - required: true, - displayOrder: 4 - } + { + label: 'Username', + key: 'username', + required: true, + placeholder: 'Username', + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + placeholder: 'Password', + type: 'password', + displayOrder: 2, + }, + { + label: 'Email', + key: 'email', + required: true, + placeholder: 'Email', + type: 'email', + displayOrder: 3, + }, + { + label: 'Phone Number', + key: 'phone_number', + placeholder: 'Phone Number', + required: true, + displayOrder: 4, + }, ]; export const signUpWithEmailFields = [ - { - label: 'Email', - key: 'email', - required: true, - placeholder: 'Email', - type: 'email', - displayOrder: 1 - }, - { - label: 'Password', - key: 'password', - required: true, - placeholder: 'Password', - type: 'password', - displayOrder: 2, - }, - { - label: 'Phone Number', - key: 'phone_number', - placeholder: 'Phone Number', - required: true, - displayOrder: 3 - } + { + label: 'Email', + key: 'email', + required: true, + placeholder: 'Email', + type: 'email', + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + placeholder: 'Password', + type: 'password', + displayOrder: 2, + }, + { + label: 'Phone Number', + key: 'phone_number', + placeholder: 'Phone Number', + required: true, + displayOrder: 3, + }, ]; export const signUpWithPhoneNumberFields = [ - { - label: 'Phone Number', - key: 'phone_number', - placeholder: 'Phone Number', - required: true, - displayOrder: 1 - }, - { - label: 'Password', - key: 'password', - required: true, - placeholder: 'Password', - type: 'password', - displayOrder: 2, - }, - { - label: 'Email', - key: 'email', - required: true, - placeholder: 'Email', - type: 'email', - displayOrder: 3 - }, + { + label: 'Phone Number', + key: 'phone_number', + placeholder: 'Phone Number', + required: true, + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + placeholder: 'Password', + type: 'password', + displayOrder: 2, + }, + { + label: 'Email', + key: 'email', + required: true, + placeholder: 'Email', + type: 'email', + displayOrder: 3, + }, ]; diff --git a/packages/aws-amplify-react/src/Auth/common/types.ts b/packages/aws-amplify-react/src/Auth/common/types.ts index 6db78658ce4..f15846cf3a5 100644 --- a/packages/aws-amplify-react/src/Auth/common/types.ts +++ b/packages/aws-amplify-react/src/Auth/common/types.ts @@ -1,5 +1,5 @@ export enum UsernameAttributes { - EMAIL = "email", - PHONE_NUMBER = "phone_number", - USERNAME = "username" + EMAIL = 'email', + PHONE_NUMBER = 'phone_number', + USERNAME = 'username', } diff --git a/packages/aws-amplify-react/src/Auth/index.jsx b/packages/aws-amplify-react/src/Auth/index.jsx index 8a36c3ff6fb..47268427178 100644 --- a/packages/aws-amplify-react/src/Auth/index.jsx +++ b/packages/aws-amplify-react/src/Auth/index.jsx @@ -27,7 +27,10 @@ export { default as ConfirmSignUp } from './ConfirmSignUp'; export { default as VerifyContact } from './VerifyContact'; export { default as ForgotPassword } from './ForgotPassword'; export { default as Greetings } from './Greetings'; -export { default as FederatedSignIn, FederatedButtons } from './FederatedSignIn'; +export { + default as FederatedSignIn, + FederatedButtons, +} from './FederatedSignIn'; export { default as TOTPSetup } from './TOTPSetup'; export { default as Loading } from './Loading'; @@ -35,99 +38,113 @@ export * from './Provider'; import Greetings from './Greetings'; - -export function withAuthenticator(Comp, includeGreetings = false, authenticatorComponents = [], federated = null, theme = null, signUpConfig = {}) { - return class extends Component { - constructor(props) { - super(props); - - this.handleAuthStateChange = this.handleAuthStateChange.bind(this); - - this.state = { - authState: props.authState || null, - authData: props.authData || null - }; - - this.authConfig = {}; - - if (typeof includeGreetings === 'object' && includeGreetings !== null){ - this.authConfig = Object.assign(this.authConfig, includeGreetings) - } else { - this.authConfig = { - includeGreetings, - authenticatorComponents, - federated, - theme, - signUpConfig - } - } - } - - handleAuthStateChange(state, data) { - this.setState({ authState: state, authData: data }); - } - - render() { - const { authState, authData } = this.state; - const signedIn = (authState === 'signedIn'); - if (signedIn) { - return ( - - { this.authConfig.includeGreetings ? - 0} - signUpConfig={this.authConfig.signUpConfig} - usernameAttributes={this.authConfig.usernameAttributes} - onStateChange={this.handleAuthStateChange} - children={this.authConfig.authenticatorComponents || []} - /> : null - } - - - ); - } - - return 0} - signUpConfig={this.authConfig.signUpConfig} - usernameAttributes={this.authConfig.usernameAttributes} - onStateChange={this.handleAuthStateChange} - children={this.authConfig.authenticatorComponents || []} - />; - } - }; +export function withAuthenticator( + Comp, + includeGreetings = false, + authenticatorComponents = [], + federated = null, + theme = null, + signUpConfig = {} +) { + return class extends Component { + constructor(props) { + super(props); + + this.handleAuthStateChange = this.handleAuthStateChange.bind(this); + + this.state = { + authState: props.authState || null, + authData: props.authData || null, + }; + + this.authConfig = {}; + + if (typeof includeGreetings === 'object' && includeGreetings !== null) { + this.authConfig = Object.assign(this.authConfig, includeGreetings); + } else { + this.authConfig = { + includeGreetings, + authenticatorComponents, + federated, + theme, + signUpConfig, + }; + } + } + + handleAuthStateChange(state, data) { + this.setState({ authState: state, authData: data }); + } + + render() { + const { authState, authData } = this.state; + const signedIn = authState === 'signedIn'; + if (signedIn) { + return ( + + {this.authConfig.includeGreetings ? ( + 0 + } + signUpConfig={this.authConfig.signUpConfig} + usernameAttributes={this.authConfig.usernameAttributes} + onStateChange={this.handleAuthStateChange} + children={this.authConfig.authenticatorComponents || []} + /> + ) : null} + + + ); + } + + return ( + 0 + } + signUpConfig={this.authConfig.signUpConfig} + usernameAttributes={this.authConfig.usernameAttributes} + onStateChange={this.handleAuthStateChange} + children={this.authConfig.authenticatorComponents || []} + /> + ); + } + }; } export class AuthenticatorWrapper extends Component { - constructor(props) { - super(props); - - this.state = { auth: 'init' }; - - this.handleAuthState = this.handleAuthState.bind(this); - } - - handleAuthState(state, data) { - this.setState({ auth: state, authData: data }); - } - - render() { - return ( -
- - {this.props.children(this.state.auth)} -
- ); - } + constructor(props) { + super(props); + + this.state = { auth: 'init' }; + + this.handleAuthState = this.handleAuthState.bind(this); + } + + handleAuthState(state, data) { + this.setState({ auth: state, authData: data }); + } + + render() { + return ( +
+ + {this.props.children(this.state.auth)} +
+ ); + } } diff --git a/packages/aws-amplify-react/src/Interactions/ChatBot.jsx b/packages/aws-amplify-react/src/Interactions/ChatBot.jsx index 41cee9e452e..82c619bc08a 100644 --- a/packages/aws-amplify-react/src/Interactions/ChatBot.jsx +++ b/packages/aws-amplify-react/src/Interactions/ChatBot.jsx @@ -1,7 +1,13 @@ import * as React from 'react'; import { Component } from 'react'; -import { Container, FormSection, SectionHeader, SectionBody, SectionFooter } from "../AmplifyUI"; -import { Input, Button } from "../AmplifyTheme"; +import { + Container, + FormSection, + SectionHeader, + SectionBody, + SectionFooter, +} from '../AmplifyUI'; +import { Input, Button } from '../AmplifyTheme'; import { I18n } from '@aws-amplify/core'; import Interactions from '@aws-amplify/interactions'; @@ -11,447 +17,515 @@ import { ConsoleLogger as Logger } from '@aws-amplify/core'; const logger = new Logger('ChatBot'); const styles = { - itemMe: { - padding: 10, - fontSize: 12, - color: 'gray', - marginTop: 4, - textAlign: 'right' - }, - itemBot: { - fontSize: 12, - textAlign: 'left' - }, - list: { - height: '300px', - overflow: 'auto', - }, - textInput: Object.assign({}, Input, { - display: 'inline-block', - width: 'calc(100% - 90px - 15px)', - }), - button: Object.assign({}, Button, { - width: '60px', - float: 'right', - }), - mic: Object.assign({}, Button, { - width: '40px', - float: 'right', - }) + itemMe: { + padding: 10, + fontSize: 12, + color: 'gray', + marginTop: 4, + textAlign: 'right', + }, + itemBot: { + fontSize: 12, + textAlign: 'left', + }, + list: { + height: '300px', + overflow: 'auto', + }, + textInput: Object.assign({}, Input, { + display: 'inline-block', + width: 'calc(100% - 90px - 15px)', + }), + button: Object.assign({}, Button, { + width: '60px', + float: 'right', + }), + mic: Object.assign({}, Button, { + width: '40px', + float: 'right', + }), }; const STATES = { - INITIAL: { MESSAGE: 'Type your message or click 🎤', ICON: '🎤'}, - LISTENING: { MESSAGE: 'Listening... click 🔴 again to cancel', ICON: '🔴'}, - SENDING: { MESSAGE: 'Please wait...', ICON: '🔊'}, - SPEAKING: { MESSAGE: 'Speaking...', ICON: '...'} + INITIAL: { MESSAGE: 'Type your message or click 🎤', ICON: '🎤' }, + LISTENING: { MESSAGE: 'Listening... click 🔴 again to cancel', ICON: '🔴' }, + SENDING: { MESSAGE: 'Please wait...', ICON: '🔊' }, + SPEAKING: { MESSAGE: 'Speaking...', ICON: '...' }, }; const defaultVoiceConfig = { - silenceDetectionConfig: { - time: 2000, - amplitude: 0.2 - } -} + silenceDetectionConfig: { + time: 2000, + amplitude: 0.2, + }, +}; let audioControl; export class ChatBot extends Component { - constructor(props) { - super(props); - - if (this.props.voiceEnabled) { - require('./aws-lex-audio.js'); - audioControl = new global.LexAudio.audioControl(); - } - if (!this.props.textEnabled && this.props.voiceEnabled) { - STATES.INITIAL.MESSAGE = 'Click the mic button'; - styles.textInput = Object.assign({}, Input, { - display: 'inline-block', - width: 'calc(100% - 40px - 15px)', - }) - } - if (this.props.textEnabled && !this.props.voiceEnabled) { - STATES.INITIAL.MESSAGE = 'Type a message'; - styles.textInput = Object.assign({}, Input, { - display: 'inline-block', - width: 'calc(100% - 60px - 15px)', - }) - } - if (!this.props.voiceConfig.silenceDetectionConfig) { - throw new Error('voiceConfig prop is missing silenceDetectionConfig'); - } - - this.state = { - dialog: [{ - message: this.props.welcomeMessage || 'Welcome to Lex', - from: 'system' - }], - inputText: '', - currentVoiceState: STATES.INITIAL, - inputDisabled: false, - micText: STATES.INITIAL.ICON, - continueConversation: false, - micButtonDisabled: false, - } - this.micButtonHandler = this.micButtonHandler.bind(this) - this.changeInputText = this.changeInputText.bind(this); - this.listItems = this.listItems.bind(this); - this.submit = this.submit.bind(this); - this.listItemsRef = React.createRef(); - this.onSilenceHandler = this.onSilenceHandler.bind(this) - this.doneSpeakingHandler = this.doneSpeakingHandler.bind(this) - this.lexResponseHandler = this.lexResponseHandler.bind(this) - } - - async micButtonHandler() { - if (this.state.continueConversation) { - this.reset(); - } else { - this.setState({ - inputDisabled: true, - continueConversation: true, - currentVoiceState: STATES.LISTENING, - micText: STATES.LISTENING.ICON, - micButtonDisabled: false, - }, () => { - audioControl.startRecording(this.onSilenceHandler, null, this.props.voiceConfig.silenceDetectionConfig); - }) - - } - } - - - onSilenceHandler() { - audioControl.stopRecording(); - if (!this.state.continueConversation) { - return; - } - audioControl.exportWAV((blob) => { - this.setState({ - currentVoiceState: STATES.SENDING, - audioInput: blob, - micText: STATES.SENDING.ICON, - micButtonDisabled: true, - }, () => { - this.lexResponseHandler(); - }) - - }); - } - - - async lexResponseHandler() { - if (!Interactions || typeof Interactions.send !== 'function') { - throw new Error('No Interactions module found, please ensure @aws-amplify/interactions is imported'); - } - if (!this.state.continueConversation) { - return; - } - - const interactionsMessage = { - content: this.state.audioInput, - options: { - messageType: 'voice' - } - }; - - const response = await Interactions.send(this.props.botName, interactionsMessage); - this.setState({ - lexResponse: response, - currentVoiceState: STATES.SPEAKING, - micText: STATES.SPEAKING.ICON, - micButtonDisabled: true, - dialog: [...this.state.dialog, - { message: response.inputTranscript, from: 'me' }, - response && { from: 'bot', message: response.message }], - inputText: '' - }, () => { - this.doneSpeakingHandler(); - }) - this.listItemsRef.current.scrollTop = this.listItemsRef.current.scrollHeight; - - } - - doneSpeakingHandler() { - if (!this.state.continueConversation) { - return; - } - if (this.state.lexResponse.contentType === 'audio/mpeg') { - audioControl.play(this.state.lexResponse.audioStream, () => { - if (this.state.lexResponse.dialogState === 'ReadyForFulfillment' || - this.state.lexResponse.dialogState === 'Fulfilled' || - this.state.lexResponse.dialogState === 'Failed' || - !this.props.conversationModeOn) { - this.setState({ - inputDisabled: false, - currentVoiceState: STATES.INITIAL, - micText: STATES.INITIAL.ICON, - micButtonDisabled: false, - continueConversation: false - }) - } else { - this.setState({ - currentVoiceState: STATES.LISTENING, - micText: STATES.LISTENING.ICON, - micButtonDisabled: false, - }, () => { - audioControl.startRecording(this.onSilenceHandler, null, this.props.voiceConfig.silenceDetectionConfig); - }) - - } - }); - } else { - this.setState({ - inputDisabled: false, - currentVoiceState: STATES.INITIAL, - micText: STATES.INITIAL.ICON, - micButtonDisabled: false, - continueConversation: false - }) - } - - } - - reset() { - this.setState({ - inputText: '', - currentVoiceState: STATES.INITIAL, - inputDisabled: false, - micText: STATES.INITIAL.ICON, - continueConversation: false, - micButtonDisabled: false, - }, () => { - audioControl.clear(); - }); - } - - listItems() { - return this.state.dialog.map((m, i) => { - if (m.from === 'me') { return
{m.message}
; } - else if (m.from === 'system') { return
{m.message}
; } - else { return
{m.message}
; } - }); - } - - async submit(e) { - e.preventDefault(); - - if (!this.state.inputText) { - return; - } - - await new Promise(resolve => this.setState({ - dialog: [ - ...this.state.dialog, - { message: this.state.inputText, from: 'me' }, - ] - }, resolve)); - - if (!Interactions || typeof Interactions.send !== 'function') { - throw new Error('No Interactions module found, please ensure @aws-amplify/interactions is imported'); - } - - const response = await Interactions.send(this.props.botName, this.state.inputText); - - this.setState({ - dialog: [...this.state.dialog, response && { from: 'bot', message: response.message }], - inputText: '' - }); - this.listItemsRef.current.scrollTop = this.listItemsRef.current.scrollHeight; - } - - async changeInputText(event) { - await this.setState({ inputText: event.target.value }); - } - - getOnComplete(fn) { - return (...args) => { - const { clearOnComplete } = this.props; - const message = fn(...args); - - this.setState( - { - dialog: [ - ...(!clearOnComplete && this.state.dialog), - message && { from: 'bot', message } - ].filter(Boolean), - }, - () => { - this.listItemsRef.current.scrollTop = this.listItemsRef.current.scrollHeight; - } - ); - }; - } - - componentDidMount() { - const {onComplete, botName} = this.props; - - if(onComplete && botName) { - if (!Interactions || typeof Interactions.onComplete !== 'function') { - throw new Error('No Interactions module found, please ensure @aws-amplify/interactions is imported'); - } - Interactions.onComplete(botName, this.getOnComplete(onComplete, this)); - } - } - - componentDidUpdate(prevProps) { - const {onComplete, botName} = this.props; - - if (botName && this.props.onComplete !== prevProps.onComplete) { - if (!Interactions || typeof Interactions.onComplete !== 'function') { - throw new Error('No Interactions module found, please ensure @aws-amplify/interactions is imported'); - } - Interactions.onComplete(botName, this.getOnComplete(onComplete, this)); - } - } - - render() { - const { title, theme, onComplete } = this.props; - - return ( - - {title && {I18n.get(title)}} - -
{this.listItems()}
-
- - - - -
- ); - } + constructor(props) { + super(props); + + if (this.props.voiceEnabled) { + require('./aws-lex-audio.js'); + audioControl = new global.LexAudio.audioControl(); + } + if (!this.props.textEnabled && this.props.voiceEnabled) { + STATES.INITIAL.MESSAGE = 'Click the mic button'; + styles.textInput = Object.assign({}, Input, { + display: 'inline-block', + width: 'calc(100% - 40px - 15px)', + }); + } + if (this.props.textEnabled && !this.props.voiceEnabled) { + STATES.INITIAL.MESSAGE = 'Type a message'; + styles.textInput = Object.assign({}, Input, { + display: 'inline-block', + width: 'calc(100% - 60px - 15px)', + }); + } + if (!this.props.voiceConfig.silenceDetectionConfig) { + throw new Error('voiceConfig prop is missing silenceDetectionConfig'); + } + + this.state = { + dialog: [ + { + message: this.props.welcomeMessage || 'Welcome to Lex', + from: 'system', + }, + ], + inputText: '', + currentVoiceState: STATES.INITIAL, + inputDisabled: false, + micText: STATES.INITIAL.ICON, + continueConversation: false, + micButtonDisabled: false, + }; + this.micButtonHandler = this.micButtonHandler.bind(this); + this.changeInputText = this.changeInputText.bind(this); + this.listItems = this.listItems.bind(this); + this.submit = this.submit.bind(this); + this.listItemsRef = React.createRef(); + this.onSilenceHandler = this.onSilenceHandler.bind(this); + this.doneSpeakingHandler = this.doneSpeakingHandler.bind(this); + this.lexResponseHandler = this.lexResponseHandler.bind(this); + } + + async micButtonHandler() { + if (this.state.continueConversation) { + this.reset(); + } else { + this.setState( + { + inputDisabled: true, + continueConversation: true, + currentVoiceState: STATES.LISTENING, + micText: STATES.LISTENING.ICON, + micButtonDisabled: false, + }, + () => { + audioControl.startRecording( + this.onSilenceHandler, + null, + this.props.voiceConfig.silenceDetectionConfig + ); + } + ); + } + } + + onSilenceHandler() { + audioControl.stopRecording(); + if (!this.state.continueConversation) { + return; + } + audioControl.exportWAV(blob => { + this.setState( + { + currentVoiceState: STATES.SENDING, + audioInput: blob, + micText: STATES.SENDING.ICON, + micButtonDisabled: true, + }, + () => { + this.lexResponseHandler(); + } + ); + }); + } + + async lexResponseHandler() { + if (!Interactions || typeof Interactions.send !== 'function') { + throw new Error( + 'No Interactions module found, please ensure @aws-amplify/interactions is imported' + ); + } + if (!this.state.continueConversation) { + return; + } + + const interactionsMessage = { + content: this.state.audioInput, + options: { + messageType: 'voice', + }, + }; + + const response = await Interactions.send( + this.props.botName, + interactionsMessage + ); + this.setState( + { + lexResponse: response, + currentVoiceState: STATES.SPEAKING, + micText: STATES.SPEAKING.ICON, + micButtonDisabled: true, + dialog: [ + ...this.state.dialog, + { message: response.inputTranscript, from: 'me' }, + response && { from: 'bot', message: response.message }, + ], + inputText: '', + }, + () => { + this.doneSpeakingHandler(); + } + ); + this.listItemsRef.current.scrollTop = this.listItemsRef.current.scrollHeight; + } + + doneSpeakingHandler() { + if (!this.state.continueConversation) { + return; + } + if (this.state.lexResponse.contentType === 'audio/mpeg') { + audioControl.play(this.state.lexResponse.audioStream, () => { + if ( + this.state.lexResponse.dialogState === 'ReadyForFulfillment' || + this.state.lexResponse.dialogState === 'Fulfilled' || + this.state.lexResponse.dialogState === 'Failed' || + !this.props.conversationModeOn + ) { + this.setState({ + inputDisabled: false, + currentVoiceState: STATES.INITIAL, + micText: STATES.INITIAL.ICON, + micButtonDisabled: false, + continueConversation: false, + }); + } else { + this.setState( + { + currentVoiceState: STATES.LISTENING, + micText: STATES.LISTENING.ICON, + micButtonDisabled: false, + }, + () => { + audioControl.startRecording( + this.onSilenceHandler, + null, + this.props.voiceConfig.silenceDetectionConfig + ); + } + ); + } + }); + } else { + this.setState({ + inputDisabled: false, + currentVoiceState: STATES.INITIAL, + micText: STATES.INITIAL.ICON, + micButtonDisabled: false, + continueConversation: false, + }); + } + } + + reset() { + this.setState( + { + inputText: '', + currentVoiceState: STATES.INITIAL, + inputDisabled: false, + micText: STATES.INITIAL.ICON, + continueConversation: false, + micButtonDisabled: false, + }, + () => { + audioControl.clear(); + } + ); + } + + listItems() { + return this.state.dialog.map((m, i) => { + if (m.from === 'me') { + return ( +
+ {m.message} +
+ ); + } else if (m.from === 'system') { + return ( +
+ {m.message} +
+ ); + } else { + return ( +
+ {m.message} +
+ ); + } + }); + } + + async submit(e) { + e.preventDefault(); + + if (!this.state.inputText) { + return; + } + + await new Promise(resolve => + this.setState( + { + dialog: [ + ...this.state.dialog, + { message: this.state.inputText, from: 'me' }, + ], + }, + resolve + ) + ); + + if (!Interactions || typeof Interactions.send !== 'function') { + throw new Error( + 'No Interactions module found, please ensure @aws-amplify/interactions is imported' + ); + } + + const response = await Interactions.send( + this.props.botName, + this.state.inputText + ); + + this.setState({ + dialog: [ + ...this.state.dialog, + response && { from: 'bot', message: response.message }, + ], + inputText: '', + }); + this.listItemsRef.current.scrollTop = this.listItemsRef.current.scrollHeight; + } + + async changeInputText(event) { + await this.setState({ inputText: event.target.value }); + } + + getOnComplete(fn) { + return (...args) => { + const { clearOnComplete } = this.props; + const message = fn(...args); + + this.setState( + { + dialog: [ + ...(!clearOnComplete && this.state.dialog), + message && { from: 'bot', message }, + ].filter(Boolean), + }, + () => { + this.listItemsRef.current.scrollTop = this.listItemsRef.current.scrollHeight; + } + ); + }; + } + + componentDidMount() { + const { onComplete, botName } = this.props; + + if (onComplete && botName) { + if (!Interactions || typeof Interactions.onComplete !== 'function') { + throw new Error( + 'No Interactions module found, please ensure @aws-amplify/interactions is imported' + ); + } + Interactions.onComplete(botName, this.getOnComplete(onComplete, this)); + } + } + + componentDidUpdate(prevProps) { + const { onComplete, botName } = this.props; + + if (botName && this.props.onComplete !== prevProps.onComplete) { + if (!Interactions || typeof Interactions.onComplete !== 'function') { + throw new Error( + 'No Interactions module found, please ensure @aws-amplify/interactions is imported' + ); + } + Interactions.onComplete(botName, this.getOnComplete(onComplete, this)); + } + } + + render() { + const { title, theme, onComplete } = this.props; + + return ( + + {title && ( + {I18n.get(title)} + )} + +
+ {this.listItems()} +
+
+ + + +
+ ); + } } function ChatBotTextInput(props) { - const styles=props.styles - const onChange=props.onChange - const inputText=props.inputText - const inputDisabled=props.inputDisabled - const currentVoiceState=props.currentVoiceState - - return( - - - ) + const styles = props.styles; + const onChange = props.onChange; + const inputText = props.inputText; + const inputDisabled = props.inputDisabled; + const currentVoiceState = props.currentVoiceState; + + return ( + + ); } function ChatBotMicButton(props) { - const voiceEnabled = props.voiceEnabled; - const styles = props.styles; - const micButtonDisabled = props.micButtonDisabled; - const handleMicButton = props.handleMicButton; - const micText = props.micText; - - if (!voiceEnabled) { - return null - } - - return( - - ) + const voiceEnabled = props.voiceEnabled; + const styles = props.styles; + const micButtonDisabled = props.micButtonDisabled; + const handleMicButton = props.handleMicButton; + const micText = props.micText; + + if (!voiceEnabled) { + return null; + } + + return ( + + ); } function ChatBotTextButton(props) { - const textEnabled = props.textEnabled; - const styles = props.styles; - const inputDisabled = props.inputDisabled; - - if (!textEnabled) { - return null; - } - - return( - - ) + const textEnabled = props.textEnabled; + const styles = props.styles; + const inputDisabled = props.inputDisabled; + + if (!textEnabled) { + return null; + } + + return ( + + ); } function ChatBotInputs(props) { - const voiceEnabled = props.voiceEnabled; - const textEnabled = props.textEnabled; - const styles = props.styles; - const onChange = props.onChange; - const inputDisabled = props.inputDisabled; - const micButtonDisabled = props.micButtonDisabled; - const inputText = props.inputText; - const onSubmit = props.onSubmit; - const handleMicButton = props.handleMicButton; - const micText = props.micText; - const currentVoiceState = props.currentVoiceState - - if (voiceEnabled && !textEnabled) { - inputDisabled = true; - } - - if (!voiceEnabled && !textEnabled) { - return(
No Chatbot inputs enabled. Set at least one of voiceEnabled or textEnabled in the props.
) - } - - return ( -
- - - - ); + const voiceEnabled = props.voiceEnabled; + const textEnabled = props.textEnabled; + const styles = props.styles; + const onChange = props.onChange; + const inputDisabled = props.inputDisabled; + const micButtonDisabled = props.micButtonDisabled; + const inputText = props.inputText; + const onSubmit = props.onSubmit; + const handleMicButton = props.handleMicButton; + const micText = props.micText; + const currentVoiceState = props.currentVoiceState; + + if (voiceEnabled && !textEnabled) { + inputDisabled = true; + } + + if (!voiceEnabled && !textEnabled) { + return ( +
+ No Chatbot inputs enabled. Set at least one of voiceEnabled or + textEnabled in the props.{' '} +
+ ); + } + + return ( +
+ + + + + ); } ChatBot.defaultProps = { - title: '', - botName: '', - onComplete: undefined, - clearOnComplete: false, - voiceConfig: defaultVoiceConfig, - conversationModeOn: false, - voiceEnabled: false, - textEnabled: true + title: '', + botName: '', + onComplete: undefined, + clearOnComplete: false, + voiceConfig: defaultVoiceConfig, + conversationModeOn: false, + voiceEnabled: false, + textEnabled: true, }; export default ChatBot; diff --git a/packages/aws-amplify-react/src/Interactions/aws-lex-audio.js b/packages/aws-amplify-react/src/Interactions/aws-lex-audio.js index 9c64b88dcb3..42740dcaff5 100644 --- a/packages/aws-amplify-react/src/Interactions/aws-lex-audio.js +++ b/packages/aws-amplify-react/src/Interactions/aws-lex-audio.js @@ -12,793 +12,977 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o amplitude || curr_value_time < (-1 * amplitude)) { - start = Date.now(); - } - } - var newtime = Date.now(); - var elapsedTime = newtime - start; - if (elapsedTime > time) { - silenceCallback(); - } - }; - - /** - * The onaudioprocess event handler of the ScriptProcessorNode interface. It is the EventHandler to be - * called for the audioprocess event that is dispatched to ScriptProcessorNode node types. - * @param {AudioProcessingEvent} audioProcessingEvent - The audio processing event. - */ - node.onaudioprocess = function (audioProcessingEvent) { - if (!recording) { - return; - } - worker.postMessage({ - command: 'record', - buffer: [ - audioProcessingEvent.inputBuffer.getChannelData(0), - ] - }); - analyse(); - }; - - var analyser = source.context.createAnalyser(); - analyser.minDecibels = -90; - analyser.maxDecibels = -10; - analyser.smoothingTimeConstant = 0.85; - - source.connect(analyser); - analyser.connect(node); - node.connect(source.context.destination); - - return { - record: record, - stop: stop, - clear: clear, - exportWAV: exportWAV - }; - }; - - /** - * Audio recorder object. Handles setting up the audio context, - * accessing the mike, and creating the Recorder object. - */ - exports.audioRecorder = function () { - - /** - * Creates an audio context and calls getUserMedia to request the mic (audio). - */ - var requestDevice = function () { - - if (typeof audio_context === 'undefined') { - window.AudioContext = window.AudioContext || window.webkitAudioContext; - audio_context = new AudioContext(); - } - - return navigator.mediaDevices.getUserMedia({audio: true}).then(function (stream) { - audio_stream = stream; - }); - }; - - var createRecorder = function (silenceDetectionConfig) { - return recorder(audio_context.createMediaStreamSource(audio_stream), silenceDetectionConfig); - }; - - var audioContext = function () { - return audio_context; - }; - - return { - requestDevice: requestDevice, - createRecorder: createRecorder, - audioContext: audioContext - }; - - }; -})(); -},{"./worker.js":6,"webworkify":4}],6:[function(require,module,exports){ -module.exports = function (self) { - 'use strict'; - var recLength = 0, - recBuffer = [], - recordSampleRate; - - self.addEventListener('message', function (e) { - switch (e.data.command) { - case 'init': - init(e.data.config); - break; - case 'record': - record(e.data.buffer); - break; - case 'export': - exportBuffer(e.data.sampleRate); - break; - case 'clear': - clear(); - break; - } - }); - - function init(config) { - recordSampleRate = config.sampleRate; - } - - function record(inputBuffer) { - recBuffer.push(inputBuffer[0]); - recLength += inputBuffer[0].length; - } - - function exportBuffer(exportSampleRate) { - var mergedBuffers = mergeBuffers(recBuffer, recLength); - var downsampledBuffer = downsampleBuffer(mergedBuffers, exportSampleRate); - var encodedWav = encodeWAV(downsampledBuffer); - var audioBlob = new Blob([encodedWav], {type: 'application/octet-stream'}); - postMessage(audioBlob); - } - - function clear() { - recLength = 0; - recBuffer = []; - } - - function downsampleBuffer(buffer, exportSampleRate) { - if (exportSampleRate === recordSampleRate) { - return buffer; - } - var sampleRateRatio = recordSampleRate / exportSampleRate; - var newLength = Math.round(buffer.length / sampleRateRatio); - var result = new Float32Array(newLength); - var offsetResult = 0; - var offsetBuffer = 0; - while (offsetResult < result.length) { - var nextOffsetBuffer = Math.round((offsetResult + 1) * sampleRateRatio); - var accum = 0, - count = 0; - for (var i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) { - accum += buffer[i]; - count++; - } - result[offsetResult] = accum / count; - offsetResult++; - offsetBuffer = nextOffsetBuffer; - } - return result; - } - - function mergeBuffers(bufferArray, recLength) { - var result = new Float32Array(recLength); - var offset = 0; - for (var i = 0; i < bufferArray.length; i++) { - result.set(bufferArray[i], offset); - offset += bufferArray[i].length; - } - return result; - } - - function floatTo16BitPCM(output, offset, input) { - for (var i = 0; i < input.length; i++, offset += 2) { - var s = Math.max(-1, Math.min(1, input[i])); - output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true); - } - } - - function writeString(view, offset, string) { - for (var i = 0; i < string.length; i++) { - view.setUint8(offset + i, string.charCodeAt(i)); - } - } - - function encodeWAV(samples) { - var buffer = new ArrayBuffer(44 + samples.length * 2); - var view = new DataView(buffer); - - writeString(view, 0, 'RIFF'); - view.setUint32(4, 32 + samples.length * 2, true); - writeString(view, 8, 'WAVE'); - writeString(view, 12, 'fmt '); - view.setUint32(16, 16, true); - view.setUint16(20, 1, true); - view.setUint16(22, 1, true); - view.setUint32(24, recordSampleRate, true); - view.setUint32(28, recordSampleRate * 2, true); - view.setUint16(32, 2, true); - view.setUint16(34, 16, true); - writeString(view, 36, 'data'); - view.setUint32(40, samples.length * 2, true); - floatTo16BitPCM(view, 44, samples); - - return view; - } -}; - -},{}]},{},[3]); +(function e(t, n, r) { + function s(o, u) { + if (!n[o]) { + if (!t[o]) { + var a = typeof require == 'function' && require; + if (!u && a) return a(o, !0); + if (i) return i(o, !0); + var f = new Error("Cannot find module '" + o + "'"); + throw ((f.code = 'MODULE_NOT_FOUND'), f); + } + var l = (n[o] = { exports: {} }); + t[o][0].call( + l.exports, + function(e) { + var n = t[o][1][e]; + return s(n ? n : e); + }, + l, + l.exports, + e, + t, + n, + r + ); + } + return n[o].exports; + } + var i = typeof require == 'function' && require; + for (var o = 0; o < r.length; o++) s(r[o]); + return s; +})( + { + 1: [ + function(require, module, exports) { + (function() { + 'use strict'; + var rec = require('./recorder.js'); + var recorder, + audioRecorder, + checkAudioSupport, + audioSupported, + playbackSource, + UNSUPPORTED = 'Audio is not supported.'; + + /** + * Represents an audio control that can start and stop recording, + * export captured audio, play an audio buffer, and check if audio + * is supported. + */ + exports.audioControl = function(options) { + options = options || {}; + this.checkAudioSupport = options.checkAudioSupport !== false; + + /** + * This callback type is called `onSilenceCallback`. + * + * @callback onSilenceCallback + */ + + /** + * Visualize callback: `visualizerCallback`. + * + * @callback visualizerCallback + * @param {Uint8Array} dataArray + * @param {number} bufferLength + */ + + /** + * Clears the previous buffer and starts buffering audio. + * + * @param {?onSilenceCallback} onSilence - Called when silence is detected. + * @param {?visualizerCallback} visualizer - Can be used to visualize the captured buffer. + * @param {silenceDetectionConfig} - Specify custom silence detection values. + * @throws {Error} If audio is not supported. + */ + var startRecording = function( + onSilence, + visualizer, + silenceDetectionConfig + ) { + onSilence = + onSilence || + function() { + /* no op */ + }; + visualizer = + visualizer || + function() { + /* no op */ + }; + audioSupported = audioSupported !== false; + if (!audioSupported) { + throw new Error(UNSUPPORTED); + } + recorder = audioRecorder.createRecorder(silenceDetectionConfig); + recorder.record(onSilence, visualizer); + }; + + /** + * Stops buffering audio. + * + * @throws {Error} If audio is not supported. + */ + var stopRecording = function() { + audioSupported = audioSupported !== false; + if (!audioSupported) { + throw new Error(UNSUPPORTED); + } + recorder.stop(); + }; + + /** + * On export complete callback: `onExportComplete`. + * + * @callback onExportComplete + * @param {Blob} blob The exported audio as a Blob. + */ + + /** + * Exports the captured audio buffer. + * + * @param {onExportComplete} callback - Called when the export is complete. + * @param {sampleRate} The sample rate to use in the export. + * @throws {Error} If audio is not supported. + */ + var exportWAV = function(callback, sampleRate) { + audioSupported = audioSupported !== false; + if (!audioSupported) { + throw new Error(UNSUPPORTED); + } + if (!(callback && typeof callback === 'function')) { + throw new Error('You must pass a callback function to export.'); + } + sampleRate = + typeof sampleRate !== 'undefined' ? sampleRate : 16000; + recorder.exportWAV(callback, sampleRate); + recorder.clear(); + }; + + /** + * On playback complete callback: `onPlaybackComplete`. + * + * @callback onPlaybackComplete + */ + + /** + * Plays the audio buffer with an HTML5 audio tag. + * @param {Uint8Array} buffer - The audio buffer to play. + * @param {?onPlaybackComplete} callback - Called when audio playback is complete. + */ + var playHtmlAudioElement = function(buffer, callback) { + if (typeof buffer === 'undefined') { + return; + } + var myBlob = new Blob([buffer]); + var audio = document.createElement('audio'); + var objectUrl = window.URL.createObjectURL(myBlob); + audio.src = objectUrl; + audio.addEventListener('ended', function() { + audio.currentTime = 0; + if (typeof callback === 'function') { + callback(); + } + }); + audio.play(); + }; + + /** + * On playback complete callback: `onPlaybackComplete`. + * + * @callback onPlaybackComplete + */ + + /** + * Plays the audio buffer with a WebAudio AudioBufferSourceNode. + * @param {Uint8Array} buffer - The audio buffer to play. + * @param {?onPlaybackComplete} callback - Called when audio playback is complete. + */ + var play = function(buffer, callback) { + if (typeof buffer === 'undefined') { + return; + } + var myBlob = new Blob([buffer]); + // We'll use a FileReader to create and ArrayBuffer out of the audio response. + var fileReader = new FileReader(); + fileReader.onload = function() { + // Once we have an ArrayBuffer we can create our BufferSource and decode the result as an AudioBuffer. + playbackSource = audioRecorder + .audioContext() + .createBufferSource(); + audioRecorder + .audioContext() + .decodeAudioData(this.result, function(buf) { + // Set the source buffer as our new AudioBuffer. + playbackSource.buffer = buf; + // Set the destination (the actual audio-rendering device--your device's speakers). + playbackSource.connect( + audioRecorder.audioContext().destination + ); + // Add an "on ended" callback. + playbackSource.onended = function(event) { + if (typeof callback === 'function') { + callback(); + } + }; + // Start the playback. + playbackSource.start(0); + }); + }; + fileReader.readAsArrayBuffer(myBlob); + }; + + /** + * Stops the playback source (created by the play method) if it exists. The `onPlaybackComplete` + * callback will be called. + */ + var stop = function() { + if (typeof playbackSource === 'undefined') { + return; + } + playbackSource.stop(); + }; + + /** + * Clear the recording buffer. + */ + var clear = function() { + recorder.clear(); + }; + + /** + * On audio supported callback: `onAudioSupported`. + * + * @callback onAudioSupported + * @param {boolean} + */ + + /** + * Checks that getUserMedia is supported and the user has given us access to the mic. + * @param {onAudioSupported} callback - Called with the result. + */ + var supportsAudio = function(callback) { + callback = + callback || + function() { + /* no op */ + }; + if ( + navigator.mediaDevices && + navigator.mediaDevices.getUserMedia + ) { + audioRecorder = rec.audioRecorder(); + audioRecorder + .requestDevice() + .then(function(stream) { + audioSupported = true; + callback(audioSupported); + }) + .catch(function(error) { + audioSupported = false; + callback(audioSupported); + }); + } else { + audioSupported = false; + callback(audioSupported); + } + }; + + if (this.checkAudioSupport) { + supportsAudio(); + } + + return { + startRecording: startRecording, + stopRecording: stopRecording, + exportWAV: exportWAV, + play: play, + stop: stop, + clear: clear, + playHtmlAudioElement: playHtmlAudioElement, + supportsAudio: supportsAudio, + }; + }; + })(); + }, + { './recorder.js': 5 }, + ], + 2: [ + function(require, module, exports) { + (function() { + 'use strict'; + var AudioControl = require('./control.js').audioControl; + + var DEFAULT_LATEST = '$LATEST'; + var DEFAULT_CONTENT_TYPE = 'audio/x-l16; sample-rate=16000'; + var DEFAULT_USER_ID = 'userId'; + var DEFAULT_ACCEPT_HEADER_VALUE = 'audio/mpeg'; + var MESSAGES = Object.freeze({ + PASSIVE: 'Passive', + LISTENING: 'Listening', + SENDING: 'Sending', + SPEAKING: 'Speaking', + }); + + var lexruntime, + audioControl = new AudioControl({ checkAudioSupport: false }); + + exports.conversation = function( + config, + onStateChange, + onSuccess, + onError, + onAudioData + ) { + var currentState; + + // Apply default values. + this.config = applyDefaults(config); + this.lexConfig = this.config.lexConfig; + this.messages = MESSAGES; + onStateChange = + onStateChange || + function() { + /* no op */ + }; + this.onSuccess = + onSuccess || + function() { + /* no op */ + }; + this.onError = + onError || + function() { + /* no op */ + }; + this.onAudioData = + onAudioData || + function() { + /* no op */ + }; + + // Validate input. + if (!this.config.lexConfig.botName) { + this.onError('A Bot name must be provided.'); + return; + } + if (!AWS.config.credentials) { + this.onError('AWS Credentials must be provided.'); + return; + } + if (!AWS.config.region) { + this.onError('A Region value must be provided.'); + return; + } + + lexruntime = new AWS.LexRuntime(); + + this.onSilence = function() { + if (config.silenceDetection) { + audioControl.stopRecording(); + currentState.advanceConversation(); + } + }; + + this.transition = function(conversation) { + currentState = conversation; + var state = currentState.state; + onStateChange(state.message); + + // If we are transitioning into SENDING or SPEAKING we want to immediately advance the conversation state + // to start the service call or playback. + if ( + state.message === state.messages.SENDING || + state.message === state.messages.SPEAKING + ) { + currentState.advanceConversation(); + } + // If we are transitioning in to sending and we are not detecting silence (this was a manual state change) + // we need to do some cleanup: stop recording, and stop rendering. + if ( + state.message === state.messages.SENDING && + !this.config.silenceDetection + ) { + audioControl.stopRecording(); + } + }; + + this.advanceConversation = function() { + audioControl.supportsAudio(function(supported) { + if (supported) { + currentState.advanceConversation(); + } else { + onError('Audio is not supported.'); + } + }); + }; + + this.updateConfig = function(newValue) { + this.config = applyDefaults(newValue); + this.lexConfig = this.config.lexConfig; + }; + + this.reset = function() { + audioControl.clear(); + currentState = new Initial(currentState.state); + }; + + currentState = new Initial(this); + + return { + advanceConversation: this.advanceConversation, + updateConfig: this.updateConfig, + reset: this.reset, + }; + }; + + var Initial = function(state) { + this.state = state; + state.message = state.messages.PASSIVE; + this.advanceConversation = function() { + audioControl.startRecording( + state.onSilence, + state.onAudioData, + state.config.silenceDetectionConfig + ); + state.transition(new Listening(state)); + }; + }; + + var Listening = function(state) { + this.state = state; + state.message = state.messages.LISTENING; + this.advanceConversation = function() { + audioControl.exportWAV(function(blob) { + state.audioInput = blob; + state.transition(new Sending(state)); + }); + }; + }; + + var Sending = function(state) { + this.state = state; + state.message = state.messages.SENDING; + this.advanceConversation = function() { + state.lexConfig.inputStream = state.audioInput; + lexruntime.postContent(state.lexConfig, function(err, data) { + if (err) { + state.onError(err); + state.transition(new Initial(state)); + } else { + state.audioOutput = data; + state.transition(new Speaking(state)); + state.onSuccess(data); + } + }); + }; + }; + + var Speaking = function(state) { + this.state = state; + state.message = state.messages.SPEAKING; + this.advanceConversation = function() { + if (state.audioOutput.contentType === 'audio/mpeg') { + audioControl.play(state.audioOutput.audioStream, function() { + if ( + state.audioOutput.dialogState === 'ReadyForFulfillment' || + state.audioOutput.dialogState === 'Fulfilled' || + state.audioOutput.dialogState === 'Failed' || + !state.config.silenceDetection + ) { + state.transition(new Initial(state)); + } else { + audioControl.startRecording( + state.onSilence, + state.onAudioData, + state.config.silenceDetectionConfig + ); + state.transition(new Listening(state)); + } + }); + } else { + state.transition(new Initial(state)); + } + }; + }; + + var applyDefaults = function(config) { + config = config || {}; + config.silenceDetection = config.hasOwnProperty('silenceDetection') + ? config.silenceDetection + : true; + + var lexConfig = config.lexConfig || {}; + lexConfig.botAlias = lexConfig.hasOwnProperty('botAlias') + ? lexConfig.botAlias + : DEFAULT_LATEST; + lexConfig.botName = lexConfig.hasOwnProperty('botName') + ? lexConfig.botName + : ''; + lexConfig.contentType = lexConfig.hasOwnProperty('contentType') + ? lexConfig.contentType + : DEFAULT_CONTENT_TYPE; + lexConfig.userId = lexConfig.hasOwnProperty('userId') + ? lexConfig.userId + : DEFAULT_USER_ID; + lexConfig.accept = lexConfig.hasOwnProperty('accept') + ? lexConfig.accept + : DEFAULT_ACCEPT_HEADER_VALUE; + config.lexConfig = lexConfig; + + return config; + }; + })(); + }, + { './control.js': 1 }, + ], + 3: [ + function(require, module, exports) { + (function(global) { + /** + * @module LexAudio + * @description The global namespace for Amazon Lex Audio + */ + global.LexAudio = global.LexAudio || {}; + global.LexAudio.audioControl = require('./control.js').audioControl; + global.LexAudio.conversation = require('./conversation.js').conversation; + module.exports = global.LexAudio; + }.call( + this, + typeof global !== 'undefined' + ? global + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : {} + )); + }, + { './control.js': 1, './conversation.js': 2 }, + ], + 4: [ + function(require, module, exports) { + var bundleFn = arguments[3]; + var sources = arguments[4]; + var cache = arguments[5]; + + var stringify = JSON.stringify; + + module.exports = function(fn, options) { + var wkey; + var cacheKeys = Object.keys(cache); + + for (var i = 0, l = cacheKeys.length; i < l; i++) { + var key = cacheKeys[i]; + var exp = cache[key].exports; + // Using babel as a transpiler to use esmodule, the export will always + // be an object with the default export as a property of it. To ensure + // the existing api and babel esmodule exports are both supported we + // check for both + if (exp === fn || (exp && exp.default === fn)) { + wkey = key; + break; + } + } + + if (!wkey) { + wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); + var wcache = {}; + for (var i = 0, l = cacheKeys.length; i < l; i++) { + var key = cacheKeys[i]; + wcache[key] = key; + } + sources[wkey] = [ + Function(['require', 'module', 'exports'], '(' + fn + ')(self)'), + wcache, + ]; + } + var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); + + var scache = {}; + scache[wkey] = wkey; + sources[skey] = [ + Function( + ['require'], + // try to call default if defined to also support babel esmodule + // exports + 'var f = require(' + + stringify(wkey) + + ');' + + '(f.default ? f.default : f)(self);' + ), + scache, + ]; + + var workerSources = {}; + resolveSources(skey); + + function resolveSources(key) { + workerSources[key] = true; + + for (var depPath in sources[key][1]) { + var depKey = sources[key][1][depPath]; + if (!workerSources[depKey]) { + resolveSources(depKey); + } + } + } + + var src = + '(' + + bundleFn + + ')({' + + Object.keys(workerSources) + .map(function(key) { + return ( + stringify(key) + + ':[' + + sources[key][0] + + ',' + + stringify(sources[key][1]) + + ']' + ); + }) + .join(',') + + '},{},[' + + stringify(skey) + + '])'; + var URL = + window.URL || window.webkitURL || window.mozURL || window.msURL; + + var blob = new Blob([src], { type: 'text/javascript' }); + if (options && options.bare) { + return blob; + } + var workerUrl = URL.createObjectURL(blob); + var worker = new Worker(workerUrl); + worker.objectURL = workerUrl; + return worker; + }; + }, + {}, + ], + 5: [ + function(require, module, exports) { + (function() { + 'use strict'; + var work = require('webworkify'); + var worker = work(require('./worker.js')); + var audio_context, audio_stream; + + /** + * The Recorder object. Sets up the onaudioprocess callback and communicates + * with the web worker to perform audio actions. + */ + var recorder = function(source, silenceDetectionConfig) { + silenceDetectionConfig = silenceDetectionConfig || {}; + silenceDetectionConfig.time = silenceDetectionConfig.hasOwnProperty( + 'time' + ) + ? silenceDetectionConfig.time + : 1500; + silenceDetectionConfig.amplitude = silenceDetectionConfig.hasOwnProperty( + 'amplitude' + ) + ? silenceDetectionConfig.amplitude + : 0.2; + + var recording = false, + currCallback, + start, + silenceCallback, + visualizationCallback; + + // Create a ScriptProcessorNode with a bufferSize of 4096 and a single input and output channel + var node = source.context.createScriptProcessor(4096, 1, 1); + + worker.onmessage = function(message) { + var blob = message.data; + currCallback(blob); + }; + + worker.postMessage({ + command: 'init', + config: { + sampleRate: source.context.sampleRate, + }, + }); + + /** + * Sets the silence and viz callbacks, resets the silence start time, and sets recording to true. + * @param {?onSilenceCallback} onSilence - Called when silence is detected. + * @param {?visualizerCallback} visualizer - Can be used to visualize the captured buffer. + */ + var record = function(onSilence, visualizer) { + silenceCallback = onSilence; + visualizationCallback = visualizer; + start = Date.now(); + recording = true; + }; + + /** + * Sets recording to false. + */ + var stop = function() { + recording = false; + }; + + /** + * Posts "clear" message to the worker. + */ + var clear = function() { + stop(); + worker.postMessage({ command: 'clear' }); + }; + + /** + * Sets the export callback and posts an "export" message to the worker. + * @param {onExportComplete} callback - Called when the export is complete. + * @param {sampleRate} The sample rate to use in the export. + */ + var exportWAV = function(callback, sampleRate) { + currCallback = callback; + worker.postMessage({ + command: 'export', + sampleRate: sampleRate, + }); + }; + + /** + * Checks the time domain data to see if the amplitude of the audio waveform is more than + * the silence threshold. If it is, "noise" has been detected and it resets the start time. + * If the elapsed time reaches the time threshold the silence callback is called. If there is a + * visualizationCallback it invokes the visualization callback with the time domain data. + */ + var analyse = function() { + analyser.fftSize = 2048; + var bufferLength = analyser.fftSize; + var dataArray = new Uint8Array(bufferLength); + var amplitude = silenceDetectionConfig.amplitude; + var time = silenceDetectionConfig.time; + + analyser.getByteTimeDomainData(dataArray); + + if (typeof visualizationCallback === 'function') { + visualizationCallback(dataArray, bufferLength); + } + + for (var i = 0; i < bufferLength; i++) { + // Normalize between -1 and 1. + var curr_value_time = dataArray[i] / 128 - 1.0; + if ( + curr_value_time > amplitude || + curr_value_time < -1 * amplitude + ) { + start = Date.now(); + } + } + var newtime = Date.now(); + var elapsedTime = newtime - start; + if (elapsedTime > time) { + silenceCallback(); + } + }; + + /** + * The onaudioprocess event handler of the ScriptProcessorNode interface. It is the EventHandler to be + * called for the audioprocess event that is dispatched to ScriptProcessorNode node types. + * @param {AudioProcessingEvent} audioProcessingEvent - The audio processing event. + */ + node.onaudioprocess = function(audioProcessingEvent) { + if (!recording) { + return; + } + worker.postMessage({ + command: 'record', + buffer: [audioProcessingEvent.inputBuffer.getChannelData(0)], + }); + analyse(); + }; + + var analyser = source.context.createAnalyser(); + analyser.minDecibels = -90; + analyser.maxDecibels = -10; + analyser.smoothingTimeConstant = 0.85; + + source.connect(analyser); + analyser.connect(node); + node.connect(source.context.destination); + + return { + record: record, + stop: stop, + clear: clear, + exportWAV: exportWAV, + }; + }; + + /** + * Audio recorder object. Handles setting up the audio context, + * accessing the mike, and creating the Recorder object. + */ + exports.audioRecorder = function() { + /** + * Creates an audio context and calls getUserMedia to request the mic (audio). + */ + var requestDevice = function() { + if (typeof audio_context === 'undefined') { + window.AudioContext = + window.AudioContext || window.webkitAudioContext; + audio_context = new AudioContext(); + } + + return navigator.mediaDevices + .getUserMedia({ audio: true }) + .then(function(stream) { + audio_stream = stream; + }); + }; + + var createRecorder = function(silenceDetectionConfig) { + return recorder( + audio_context.createMediaStreamSource(audio_stream), + silenceDetectionConfig + ); + }; + + var audioContext = function() { + return audio_context; + }; + + return { + requestDevice: requestDevice, + createRecorder: createRecorder, + audioContext: audioContext, + }; + }; + })(); + }, + { './worker.js': 6, webworkify: 4 }, + ], + 6: [ + function(require, module, exports) { + module.exports = function(self) { + 'use strict'; + var recLength = 0, + recBuffer = [], + recordSampleRate; + + self.addEventListener('message', function(e) { + switch (e.data.command) { + case 'init': + init(e.data.config); + break; + case 'record': + record(e.data.buffer); + break; + case 'export': + exportBuffer(e.data.sampleRate); + break; + case 'clear': + clear(); + break; + } + }); + + function init(config) { + recordSampleRate = config.sampleRate; + } + + function record(inputBuffer) { + recBuffer.push(inputBuffer[0]); + recLength += inputBuffer[0].length; + } + + function exportBuffer(exportSampleRate) { + var mergedBuffers = mergeBuffers(recBuffer, recLength); + var downsampledBuffer = downsampleBuffer( + mergedBuffers, + exportSampleRate + ); + var encodedWav = encodeWAV(downsampledBuffer); + var audioBlob = new Blob([encodedWav], { + type: 'application/octet-stream', + }); + postMessage(audioBlob); + } + + function clear() { + recLength = 0; + recBuffer = []; + } + + function downsampleBuffer(buffer, exportSampleRate) { + if (exportSampleRate === recordSampleRate) { + return buffer; + } + var sampleRateRatio = recordSampleRate / exportSampleRate; + var newLength = Math.round(buffer.length / sampleRateRatio); + var result = new Float32Array(newLength); + var offsetResult = 0; + var offsetBuffer = 0; + while (offsetResult < result.length) { + var nextOffsetBuffer = Math.round( + (offsetResult + 1) * sampleRateRatio + ); + var accum = 0, + count = 0; + for ( + var i = offsetBuffer; + i < nextOffsetBuffer && i < buffer.length; + i++ + ) { + accum += buffer[i]; + count++; + } + result[offsetResult] = accum / count; + offsetResult++; + offsetBuffer = nextOffsetBuffer; + } + return result; + } + + function mergeBuffers(bufferArray, recLength) { + var result = new Float32Array(recLength); + var offset = 0; + for (var i = 0; i < bufferArray.length; i++) { + result.set(bufferArray[i], offset); + offset += bufferArray[i].length; + } + return result; + } + + function floatTo16BitPCM(output, offset, input) { + for (var i = 0; i < input.length; i++, offset += 2) { + var s = Math.max(-1, Math.min(1, input[i])); + output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true); + } + } + + function writeString(view, offset, string) { + for (var i = 0; i < string.length; i++) { + view.setUint8(offset + i, string.charCodeAt(i)); + } + } + + function encodeWAV(samples) { + var buffer = new ArrayBuffer(44 + samples.length * 2); + var view = new DataView(buffer); + + writeString(view, 0, 'RIFF'); + view.setUint32(4, 32 + samples.length * 2, true); + writeString(view, 8, 'WAVE'); + writeString(view, 12, 'fmt '); + view.setUint32(16, 16, true); + view.setUint16(20, 1, true); + view.setUint16(22, 1, true); + view.setUint32(24, recordSampleRate, true); + view.setUint32(28, recordSampleRate * 2, true); + view.setUint16(32, 2, true); + view.setUint16(34, 16, true); + writeString(view, 36, 'data'); + view.setUint32(40, samples.length * 2, true); + floatTo16BitPCM(view, 44, samples); + + return view; + } + }; + }, + {}, + ], + }, + {}, + [3] +); diff --git a/packages/aws-amplify-react/src/Storage/Common.js b/packages/aws-amplify-react/src/Storage/Common.js index af3ca96eed9..b29a0022bdc 100644 --- a/packages/aws-amplify-react/src/Storage/Common.js +++ b/packages/aws-amplify-react/src/Storage/Common.js @@ -12,21 +12,21 @@ */ export function calcKey(file, fileToKey) { - const { name, size, type } = file; - let key = encodeURI(name); - if (fileToKey) { - const callback_type = typeof fileToKey; - if (callback_type === 'string') { - key = fileToKey; - } else if (callback_type === 'function') { - key = fileToKey({ name, size, type }); - } else { - key = encodeURI(JSON.stringify(fileToKey)); - } - if (!key) { - key = 'empty_key'; - } - } + const { name, size, type } = file; + let key = encodeURI(name); + if (fileToKey) { + const callback_type = typeof fileToKey; + if (callback_type === 'string') { + key = fileToKey; + } else if (callback_type === 'function') { + key = fileToKey({ name, size, type }); + } else { + key = encodeURI(JSON.stringify(fileToKey)); + } + if (!key) { + key = 'empty_key'; + } + } - return key.replace(/\s/g, '_'); + return key.replace(/\s/g, '_'); } diff --git a/packages/aws-amplify-react/src/Storage/S3Album.js b/packages/aws-amplify-react/src/Storage/S3Album.js index 3554ca176fc..379adc83c0b 100644 --- a/packages/aws-amplify-react/src/Storage/S3Album.js +++ b/packages/aws-amplify-react/src/Storage/S3Album.js @@ -25,239 +25,267 @@ import S3Text from './S3Text'; const logger = new Logger('Storage.S3Album'); export default class S3Album extends Component { - _isMounted = false; - constructor(props) { - super(props); - - this.handlePick = this.handlePick.bind(this); - this.handleClick = this.handleClick.bind(this); - this.list = this.list.bind(this); - this.marshal = this.marshal.bind(this); - - this.state = { - items: [], - ts: new Date().getTime(), - }; - } - - getKey(file) { - const { fileToKey } = this.props; - - const { name, size, type } = file; - let key = encodeURI(name); - if (fileToKey) { - const callback_type = typeof fileToKey; - if (callback_type === 'string') { - key = fileToKey; - } else if (callback_type === 'function') { - key = fileToKey({ name, size, type }); - } else { - key = encodeURI(JSON.stringify(fileToKey)); - } - if (!key) { - logger.debug('key is empty'); - key = 'empty_key'; - } - } - - return key.replace(/\s/g, '_'); - } - - handlePick(data) { - const { onPick, onLoad, onError, track, level } = this.props; - - if (onPick) { onPick(data); } - - const path = this.props.path || ''; - const { file, name, size, type } = data; - const key = path + this.getKey(data); - if (!Storage || typeof Storage.put !== 'function') { - throw new Error('No Storage module found, please ensure @aws-amplify/storage is imported'); - } - - Storage.put(key, file, { - level: level ? level : 'public', - contentType: type, - track - }) - .then(data => { - logger.debug('handle pick data', data); - const { items } = this.state; - if (items.filter(item => item.key === key).length === 0) { - const list = items.concat(data); - this.marshal(list); - } else { - logger.debug('update an item'); - } - if (onLoad) { onLoad(data); } - }) - .catch(err => { - logger.debug('handle pick error', err); - if (onError) { onError(err); } - }); - if (this._isMounted) { - this.setState({ ts: new Date().getTime() }); - } - } - - handleClick(item) { - const { onClickItem, select, onSelect } = this.props; - if (onClickItem) { onClickItem(item); } - - if (!select) { return; } - - item.selected = !item.selected; - if (this._isMounted) { - this.setState({ items: this.state.items.slice() }); - } - - if (!onSelect) { return; } - - const selected_items = this.state.items.filter(item => item.selected); - onSelect(item, selected_items); - } - - componentDidMount() { - this._isMounted = true; - this.list(); - } - - componentWillUnmount() { - this._isMounted = false; - } - - componentDidUpdate(prevProps, prevState) { - if (this.props.path === prevProps.path && - this.props.ts === prevProps.ts && - this.props.select === prevProps.select - ) { - return; - } - - if (!this.props.select) { - this.state.items.forEach(item => item.selected = false); - } - if (this.props.onSelect) { - this.props.onSelect(null, []); - } - - this.list(); - } - - list() { - const { path, level, track, identityId } = this.props; - logger.debug('Album path: ' + path); - if (!Storage || typeof Storage.list !== 'function') { - throw new Error('No Storage module found, please ensure @aws-amplify/storage is imported'); - } - return Storage.list(path, { level: level ? level : 'public', track, identityId }) - .then(data => { - logger.debug('album list', data); - this.marshal(data); - }) - .catch(err => { - logger.warn(err); - return []; - }); - } - - contentType(item) { - return JS.filenameToContentType(item.key, 'image/*'); - } - - marshal(list) { - const contentType = this.props.contentType || ''; - list.forEach(item => { - if (item.contentType) { return; } - const isString = typeof contentType === 'string'; - item.contentType = isString ? contentType : contentType(item); - if (!item.contentType) { item.contentType = this.contentType(item); } - }); - - let items = this.filter(list); - items = this.sort(items); - if (this._isMounted) { - this.setState({ items }); - } - } - - filter(list) { - const { filter } = this.props; - return filter ? filter(list) : list; - } - - sort(list) { - const { sort } = this.props; - const typeof_sort = typeof sort; - if (typeof_sort === 'function') { return sort(list); } - - if (['string', 'undefined'].includes(typeof_sort)) { - const sort_str = sort ? sort : 'lastModified'; - const parts = sort_str.split(/\s+/); - const field = parts[0]; - let dir = parts.length > 1 ? parts[1] : ''; - if (field === 'lastModified') { - dir = (dir === 'asc') ? 'asc' : 'desc'; - } else { - dir = (dir === 'desc') ? 'desc' : 'asc'; - } - JS.sortByField(list, field, dir); - - return list; - } - - logger.warn('invalid sort. done nothing. should be a string or function'); - return list; - } - - render() { - const { picker, translateItem, level, identityId } = this.props; - const { items, ts } = this.state; - - const pickerTitle = this.props.pickerTitle || 'Pick'; - - const theme = this.props.theme || AmplifyTheme; - - const list = items.map(item => { - const isText = item.contentType && JS.isTextFile(item.contentType); - return isText ? this.handleClick(item)} - /> - : this.handleClick(item)} - />; - }); - return ( -
-
- {list} -
- {picker ? - : null - } -
- ); - } + _isMounted = false; + constructor(props) { + super(props); + + this.handlePick = this.handlePick.bind(this); + this.handleClick = this.handleClick.bind(this); + this.list = this.list.bind(this); + this.marshal = this.marshal.bind(this); + + this.state = { + items: [], + ts: new Date().getTime(), + }; + } + + getKey(file) { + const { fileToKey } = this.props; + + const { name, size, type } = file; + let key = encodeURI(name); + if (fileToKey) { + const callback_type = typeof fileToKey; + if (callback_type === 'string') { + key = fileToKey; + } else if (callback_type === 'function') { + key = fileToKey({ name, size, type }); + } else { + key = encodeURI(JSON.stringify(fileToKey)); + } + if (!key) { + logger.debug('key is empty'); + key = 'empty_key'; + } + } + + return key.replace(/\s/g, '_'); + } + + handlePick(data) { + const { onPick, onLoad, onError, track, level } = this.props; + + if (onPick) { + onPick(data); + } + + const path = this.props.path || ''; + const { file, name, size, type } = data; + const key = path + this.getKey(data); + if (!Storage || typeof Storage.put !== 'function') { + throw new Error( + 'No Storage module found, please ensure @aws-amplify/storage is imported' + ); + } + + Storage.put(key, file, { + level: level ? level : 'public', + contentType: type, + track, + }) + .then(data => { + logger.debug('handle pick data', data); + const { items } = this.state; + if (items.filter(item => item.key === key).length === 0) { + const list = items.concat(data); + this.marshal(list); + } else { + logger.debug('update an item'); + } + if (onLoad) { + onLoad(data); + } + }) + .catch(err => { + logger.debug('handle pick error', err); + if (onError) { + onError(err); + } + }); + if (this._isMounted) { + this.setState({ ts: new Date().getTime() }); + } + } + + handleClick(item) { + const { onClickItem, select, onSelect } = this.props; + if (onClickItem) { + onClickItem(item); + } + + if (!select) { + return; + } + + item.selected = !item.selected; + if (this._isMounted) { + this.setState({ items: this.state.items.slice() }); + } + + if (!onSelect) { + return; + } + + const selected_items = this.state.items.filter(item => item.selected); + onSelect(item, selected_items); + } + + componentDidMount() { + this._isMounted = true; + this.list(); + } + + componentWillUnmount() { + this._isMounted = false; + } + + componentDidUpdate(prevProps, prevState) { + if ( + this.props.path === prevProps.path && + this.props.ts === prevProps.ts && + this.props.select === prevProps.select + ) { + return; + } + + if (!this.props.select) { + this.state.items.forEach(item => (item.selected = false)); + } + if (this.props.onSelect) { + this.props.onSelect(null, []); + } + + this.list(); + } + + list() { + const { path, level, track, identityId } = this.props; + logger.debug('Album path: ' + path); + if (!Storage || typeof Storage.list !== 'function') { + throw new Error( + 'No Storage module found, please ensure @aws-amplify/storage is imported' + ); + } + return Storage.list(path, { + level: level ? level : 'public', + track, + identityId, + }) + .then(data => { + logger.debug('album list', data); + this.marshal(data); + }) + .catch(err => { + logger.warn(err); + return []; + }); + } + + contentType(item) { + return JS.filenameToContentType(item.key, 'image/*'); + } + + marshal(list) { + const contentType = this.props.contentType || ''; + list.forEach(item => { + if (item.contentType) { + return; + } + const isString = typeof contentType === 'string'; + item.contentType = isString ? contentType : contentType(item); + if (!item.contentType) { + item.contentType = this.contentType(item); + } + }); + + let items = this.filter(list); + items = this.sort(items); + if (this._isMounted) { + this.setState({ items }); + } + } + + filter(list) { + const { filter } = this.props; + return filter ? filter(list) : list; + } + + sort(list) { + const { sort } = this.props; + const typeof_sort = typeof sort; + if (typeof_sort === 'function') { + return sort(list); + } + + if (['string', 'undefined'].includes(typeof_sort)) { + const sort_str = sort ? sort : 'lastModified'; + const parts = sort_str.split(/\s+/); + const field = parts[0]; + let dir = parts.length > 1 ? parts[1] : ''; + if (field === 'lastModified') { + dir = dir === 'asc' ? 'asc' : 'desc'; + } else { + dir = dir === 'desc' ? 'desc' : 'asc'; + } + JS.sortByField(list, field, dir); + + return list; + } + + logger.warn('invalid sort. done nothing. should be a string or function'); + return list; + } + + render() { + const { picker, translateItem, level, identityId } = this.props; + const { items, ts } = this.state; + + const pickerTitle = this.props.pickerTitle || 'Pick'; + + const theme = this.props.theme || AmplifyTheme; + + const list = items.map(item => { + const isText = item.contentType && JS.isTextFile(item.contentType); + return isText ? ( + this.handleClick(item)} + /> + ) : ( + this.handleClick(item)} + /> + ); + }); + return ( +
+
{list}
+ {picker ? ( + + ) : null} +
+ ); + } } diff --git a/packages/aws-amplify-react/src/Storage/S3Image.js b/packages/aws-amplify-react/src/Storage/S3Image.js index 7d0ee95b026..1f5e999bf36 100644 --- a/packages/aws-amplify-react/src/Storage/S3Image.js +++ b/packages/aws-amplify-react/src/Storage/S3Image.js @@ -25,167 +25,194 @@ import { calcKey } from './Common'; const logger = new Logger('Storage.S3Image'); export default class S3Image extends Component { - _isMounted = false; - constructor(props) { - super(props); - - this.handleOnLoad = this.handleOnLoad.bind(this); - this.handleOnError = this.handleOnError.bind(this); - this.handlePick = this.handlePick.bind(this); - this.handleClick = this.handleClick.bind(this); - - const initSrc = this.props.src || transparent1X1; - - this.state = { src: initSrc }; - } - - getImageSource(key, level, track, identityId) { - if (!Storage || typeof Storage.get !== 'function') { - throw new Error('No Storage module found, please ensure @aws-amplify/storage is imported'); - } - Storage.get(key, { level: level ? level : 'public', track, identityId }) - .then(url => { - if (this._isMounted) { - this.setState({ - src: url - }); - } - }) - .catch(err => logger.debug(err)); - } - - load() { - const { imgKey, path, body, contentType, level, track, identityId } = this.props; - if (!imgKey && !path) { - logger.debug('empty imgKey and path'); - return; - } - - const that = this; - const key = imgKey || path; - logger.debug('loading ' + key + '...'); - if (body) { - const type = contentType || 'binary/octet-stream'; - if (!Storage || typeof Storage.put !== 'function') { - throw new Error('No Storage module found, please ensure @aws-amplify/storage is imported'); - } - const ret = Storage.put(key, body, { - contentType: type, - level: level ? level : 'public', - track - }); - ret.then(data => { - logger.debug(data); - that.getImageSource(key, level, track, identityId); - }) - .catch(err => logger.debug(err)); - } else { - that.getImageSource(key, level, track, identityId); - } - } - - handleOnLoad(evt) { - const { onLoad } = this.props; - if (onLoad) { onLoad(this.state.src); } - } - - handleOnError(evt) { - const { onError } = this.props; - if (onError) { onError(this.state.src); } - } - - handlePick(data) { - const that = this; - - const path = this.props.path || ''; - const { imgKey, level, fileToKey, track, identityId } = this.props; - const { file, name, size, type } = data; - const key = imgKey || (path + calcKey(data, fileToKey)); - if (!Storage || typeof Storage.put !== 'function') { - throw new Error('No Storage module found, please ensure @aws-amplify/storage is imported'); - } - Storage.put(key, file, { - level: level ? level : 'public', - contentType: type, - track - }) - .then(data => { - logger.debug('handle pick data', data); - that.getImageSource(key, level, track, identityId); - }) - .catch(err => logger.debug('handle pick error', err)); - } - - handleClick(evt) { - const { onClick } = this.props; - if (onClick) { onClick(evt); } - } - - componentDidMount() { - this._isMounted = true; - this.load(); - } - - componentWillUnmount() { - this._isMounted = false; - } - - componentDidUpdate(prevProps) { - const update = prevProps.path !== this.props.path || - prevProps.imgKey !== this.props.imgKey || - prevProps.body !== this.props.body || - prevProps.level !== this.props.level; - if (update) { - this.load(); - } - } - - imageEl(src, theme) { - if (!src) { return null; } - - const { selected } = this.props; - const containerStyle = { position: 'relative' }; - return ( -
- -
-
- ); - } - - render() { - const { hidden, style, picker, translate, imgKey } = this.props; - let src = this.state.src; - if (translate) { - src = (typeof translate === 'string') ? translate : translate({ - type: 'image', - key: imgKey, - content: src - }); - } - if (!src && !picker) { return null; } - - const theme = this.props.theme || AmplifyTheme; - const photoStyle = hidden ? AmplifyTheme.hidden - : Object.assign({}, theme.photo, style); - - return ( -
- {photoStyle ? this.imageEl(src, theme) : null} - {picker ?
- -
: null - } -
- ); - } + _isMounted = false; + constructor(props) { + super(props); + + this.handleOnLoad = this.handleOnLoad.bind(this); + this.handleOnError = this.handleOnError.bind(this); + this.handlePick = this.handlePick.bind(this); + this.handleClick = this.handleClick.bind(this); + + const initSrc = this.props.src || transparent1X1; + + this.state = { src: initSrc }; + } + + getImageSource(key, level, track, identityId) { + if (!Storage || typeof Storage.get !== 'function') { + throw new Error( + 'No Storage module found, please ensure @aws-amplify/storage is imported' + ); + } + Storage.get(key, { level: level ? level : 'public', track, identityId }) + .then(url => { + if (this._isMounted) { + this.setState({ + src: url, + }); + } + }) + .catch(err => logger.debug(err)); + } + + load() { + const { + imgKey, + path, + body, + contentType, + level, + track, + identityId, + } = this.props; + if (!imgKey && !path) { + logger.debug('empty imgKey and path'); + return; + } + + const that = this; + const key = imgKey || path; + logger.debug('loading ' + key + '...'); + if (body) { + const type = contentType || 'binary/octet-stream'; + if (!Storage || typeof Storage.put !== 'function') { + throw new Error( + 'No Storage module found, please ensure @aws-amplify/storage is imported' + ); + } + const ret = Storage.put(key, body, { + contentType: type, + level: level ? level : 'public', + track, + }); + ret + .then(data => { + logger.debug(data); + that.getImageSource(key, level, track, identityId); + }) + .catch(err => logger.debug(err)); + } else { + that.getImageSource(key, level, track, identityId); + } + } + + handleOnLoad(evt) { + const { onLoad } = this.props; + if (onLoad) { + onLoad(this.state.src); + } + } + + handleOnError(evt) { + const { onError } = this.props; + if (onError) { + onError(this.state.src); + } + } + + handlePick(data) { + const that = this; + + const path = this.props.path || ''; + const { imgKey, level, fileToKey, track, identityId } = this.props; + const { file, name, size, type } = data; + const key = imgKey || path + calcKey(data, fileToKey); + if (!Storage || typeof Storage.put !== 'function') { + throw new Error( + 'No Storage module found, please ensure @aws-amplify/storage is imported' + ); + } + Storage.put(key, file, { + level: level ? level : 'public', + contentType: type, + track, + }) + .then(data => { + logger.debug('handle pick data', data); + that.getImageSource(key, level, track, identityId); + }) + .catch(err => logger.debug('handle pick error', err)); + } + + handleClick(evt) { + const { onClick } = this.props; + if (onClick) { + onClick(evt); + } + } + + componentDidMount() { + this._isMounted = true; + this.load(); + } + + componentWillUnmount() { + this._isMounted = false; + } + + componentDidUpdate(prevProps) { + const update = + prevProps.path !== this.props.path || + prevProps.imgKey !== this.props.imgKey || + prevProps.body !== this.props.body || + prevProps.level !== this.props.level; + if (update) { + this.load(); + } + } + + imageEl(src, theme) { + if (!src) { + return null; + } + + const { selected } = this.props; + const containerStyle = { position: 'relative' }; + return ( +
+ +
+
+ ); + } + + render() { + const { hidden, style, picker, translate, imgKey } = this.props; + let src = this.state.src; + if (translate) { + src = + typeof translate === 'string' + ? translate + : translate({ + type: 'image', + key: imgKey, + content: src, + }); + } + if (!src && !picker) { + return null; + } + + const theme = this.props.theme || AmplifyTheme; + const photoStyle = hidden + ? AmplifyTheme.hidden + : Object.assign({}, theme.photo, style); + + return ( +
+ {photoStyle ? this.imageEl(src, theme) : null} + {picker ? ( +
+ +
+ ) : null} +
+ ); + } } diff --git a/packages/aws-amplify-react/src/Storage/S3Text.js b/packages/aws-amplify-react/src/Storage/S3Text.js index cf84c9d0abd..26f1b9a60a6 100644 --- a/packages/aws-amplify-react/src/Storage/S3Text.js +++ b/packages/aws-amplify-react/src/Storage/S3Text.js @@ -24,168 +24,199 @@ import { calcKey } from './Common'; const logger = new Logger('Storage.S3Text'); export default class S3Text extends Component { - _isMounted = false; - constructor(props) { - super(props); - - this.handleOnLoad = this.handleOnLoad.bind(this); - this.handleOnError = this.handleOnError.bind(this); - this.handlePick = this.handlePick.bind(this); - this.handleClick = this.handleClick.bind(this); - - const { text, textKey } = props; - this.state = { - text: text || '', - textKey: textKey || '', - }; - } - - getText(key, level, track, identityId) { - if (!Storage || typeof Storage.get !== 'function') { - throw new Error('No Storage module found, please ensure @aws-amplify/storage is imported'); - } - Storage.get(key, { download: true, level: level ? level : 'public', track, identityId }) - .then(data => { - logger.debug(data); - const text = data.Body.toString('utf8'); - if (this._isMounted) { - this.setState({ text }); - } - this.handleOnLoad(text); - }) - .catch(err => { - logger.debug(err); - this.handleOnError(err); - }); - } - - load() { - const { path, textKey, body, contentType, level, track, identityId } = this.props; - if (!textKey && !path) { - logger.debug('empty textKey and path'); - return; - } - - const that = this; - const key = textKey || path; - logger.debug('loading ' + key + '...'); - if (body) { - const type = contentType || 'text/*'; - if (!Storage || typeof Storage.put !== 'function') { - throw new Error('No Storage module found, please ensure @aws-amplify/storage is imported'); - } - const ret = Storage.put(key, body, { - contentType: type, - level: level ? level : 'public', - track - }); - ret.then(data => { - logger.debug(data); - that.getText(key, level, track, identityId); - }) - .catch(err => logger.debug(err)); - } else { - that.getText(key, level, track, identityId); - } - } - - handleOnLoad(text) { - const { onLoad } = this.props; - if (onLoad) { onLoad(text); } - } - - handleOnError(err) { - const { onError } = this.props; - if (onError) { onError(err); } - } - - handlePick(data) { - const that = this; - - const path = this.props.path || ''; - const { textKey, level, fileToKey, track, identityId } = this.props; - const { file, name, size, type } = data; - const key = textKey || (path + calcKey(data, fileToKey)); - if (!Storage || typeof Storage.put !== 'function') { - throw new Error('No Storage module found, please ensure @aws-amplify/storage is imported'); - } - Storage.put(key, file, { - level: level ? level : 'public', - contentType: type, - track - }) - .then(data => { - logger.debug('handle pick data', data); - that.getText(key, level, track, identityId); - }) - .catch(err => logger.debug('handle pick error', err)); - } - - handleClick(evt) { - const { onClick } = this.props; - if (onClick) { onClick(evt); } - } - - componentDidMount() { - this._isMounted = true; - this.load(); - } - - componentWillUnmount() { - this._isMounted = false; - } - - componentDidUpdate(prevProps) { - const update = prevProps.path !== this.props.path || - prevProps.textKey !== this.props.textKey || - prevProps.body !== this.props.body - if (update) { - this.load(); - } - } - - textEl(text, theme) { - if (!text) { return null; } - - const { selected } = this.props; - const containerStyle = { position: 'relative' }; - return ( -
-
{text}
-
-
- ); - } - - render() { - const { hidden, style, picker, translate, textKey } = this.props; - let text = this.state.text; - if (translate) { - text = (typeof translate === 'string') ? translate : translate({ - type: 'text', - key: textKey, - content: text - }); - } - if (!text && !picker) { return null; } - - const theme = this.props.theme || AmplifyTheme; - const textStyle = hidden ? AmplifyTheme.hidden - : Object.assign({}, theme.text, style); - - return ( -
- {textStyle ? this.textEl(text, theme) : null} - {picker ?
- -
- : null - } -
- ); - } + _isMounted = false; + constructor(props) { + super(props); + + this.handleOnLoad = this.handleOnLoad.bind(this); + this.handleOnError = this.handleOnError.bind(this); + this.handlePick = this.handlePick.bind(this); + this.handleClick = this.handleClick.bind(this); + + const { text, textKey } = props; + this.state = { + text: text || '', + textKey: textKey || '', + }; + } + + getText(key, level, track, identityId) { + if (!Storage || typeof Storage.get !== 'function') { + throw new Error( + 'No Storage module found, please ensure @aws-amplify/storage is imported' + ); + } + Storage.get(key, { + download: true, + level: level ? level : 'public', + track, + identityId, + }) + .then(data => { + logger.debug(data); + const text = data.Body.toString('utf8'); + if (this._isMounted) { + this.setState({ text }); + } + this.handleOnLoad(text); + }) + .catch(err => { + logger.debug(err); + this.handleOnError(err); + }); + } + + load() { + const { + path, + textKey, + body, + contentType, + level, + track, + identityId, + } = this.props; + if (!textKey && !path) { + logger.debug('empty textKey and path'); + return; + } + + const that = this; + const key = textKey || path; + logger.debug('loading ' + key + '...'); + if (body) { + const type = contentType || 'text/*'; + if (!Storage || typeof Storage.put !== 'function') { + throw new Error( + 'No Storage module found, please ensure @aws-amplify/storage is imported' + ); + } + const ret = Storage.put(key, body, { + contentType: type, + level: level ? level : 'public', + track, + }); + ret + .then(data => { + logger.debug(data); + that.getText(key, level, track, identityId); + }) + .catch(err => logger.debug(err)); + } else { + that.getText(key, level, track, identityId); + } + } + + handleOnLoad(text) { + const { onLoad } = this.props; + if (onLoad) { + onLoad(text); + } + } + + handleOnError(err) { + const { onError } = this.props; + if (onError) { + onError(err); + } + } + + handlePick(data) { + const that = this; + + const path = this.props.path || ''; + const { textKey, level, fileToKey, track, identityId } = this.props; + const { file, name, size, type } = data; + const key = textKey || path + calcKey(data, fileToKey); + if (!Storage || typeof Storage.put !== 'function') { + throw new Error( + 'No Storage module found, please ensure @aws-amplify/storage is imported' + ); + } + Storage.put(key, file, { + level: level ? level : 'public', + contentType: type, + track, + }) + .then(data => { + logger.debug('handle pick data', data); + that.getText(key, level, track, identityId); + }) + .catch(err => logger.debug('handle pick error', err)); + } + + handleClick(evt) { + const { onClick } = this.props; + if (onClick) { + onClick(evt); + } + } + + componentDidMount() { + this._isMounted = true; + this.load(); + } + + componentWillUnmount() { + this._isMounted = false; + } + + componentDidUpdate(prevProps) { + const update = + prevProps.path !== this.props.path || + prevProps.textKey !== this.props.textKey || + prevProps.body !== this.props.body; + if (update) { + this.load(); + } + } + + textEl(text, theme) { + if (!text) { + return null; + } + + const { selected } = this.props; + const containerStyle = { position: 'relative' }; + return ( +
+
{text}
+
+
+ ); + } + + render() { + const { hidden, style, picker, translate, textKey } = this.props; + let text = this.state.text; + if (translate) { + text = + typeof translate === 'string' + ? translate + : translate({ + type: 'text', + key: textKey, + content: text, + }); + } + if (!text && !picker) { + return null; + } + + const theme = this.props.theme || AmplifyTheme; + const textStyle = hidden + ? AmplifyTheme.hidden + : Object.assign({}, theme.text, style); + + return ( +
+ {textStyle ? this.textEl(text, theme) : null} + {picker ? ( +
+ +
+ ) : null} +
+ ); + } } diff --git a/packages/aws-amplify-react/src/Widget/PhotoPicker.js b/packages/aws-amplify-react/src/Widget/PhotoPicker.js index f0f27db6bf3..b4c07dfc5e9 100644 --- a/packages/aws-amplify-react/src/Widget/PhotoPicker.js +++ b/packages/aws-amplify-react/src/Widget/PhotoPicker.js @@ -17,80 +17,89 @@ import { Component } from 'react'; import { I18n, ConsoleLogger as Logger } from '@aws-amplify/core'; import Picker from './Picker'; import AmplifyTheme from '../Amplify-UI/Amplify-UI-Theme'; -import { FormSection, SectionHeader, SectionBody, PhotoPlaceholder } from '../Amplify-UI/Amplify-UI-Components-React'; - +import { + FormSection, + SectionHeader, + SectionBody, + PhotoPlaceholder, +} from '../Amplify-UI/Amplify-UI-Components-React'; const PickerPreview = { - maxWidth: '100%' + maxWidth: '100%', }; const logger = new Logger('PhotoPicker'); export default class PhotoPicker extends Component { - constructor(props) { - super(props); - - this.handlePick = this.handlePick.bind(this); - - this.state = { - previewSrc: props.previewSrc - }; - } - - handlePick(data) { - const that = this; - const { file, name, size, type } = data; - const { preview, onPick, onLoad } = this.props; - - if (onPick) { onPick(data); } - - if (preview) { - const reader = new FileReader(); - reader.onload = function(e) { - const url = e.target.result; - that.setState({ previewSrc: url }); - if (onLoad) { onLoad(url); } - }; - reader.readAsDataURL(file); - } - } - - render() { - const { preview } = this.props; - const { previewSrc } = this.state; - - const headerText = this.props.headerText || 'Photos'; - const headerHint = this.props.headerHint || 'Add your photos by clicking below'; - const title = this.props.title || 'Select a Photo'; - - const theme = this.props.theme || AmplifyTheme; - const previewStyle = Object.assign( - {}, - PickerPreview, - theme.pickerPreview - ); - - const previewHidden = !(preview && preview !== 'hidden'); - - return ( - - {I18n.get(headerText)} - - { previewSrc ? - (previewHidden ? - 'The image has been selected': - - ): - - } - - - - ); - } + constructor(props) { + super(props); + + this.handlePick = this.handlePick.bind(this); + + this.state = { + previewSrc: props.previewSrc, + }; + } + + handlePick(data) { + const that = this; + const { file, name, size, type } = data; + const { preview, onPick, onLoad } = this.props; + + if (onPick) { + onPick(data); + } + + if (preview) { + const reader = new FileReader(); + reader.onload = function(e) { + const url = e.target.result; + that.setState({ previewSrc: url }); + if (onLoad) { + onLoad(url); + } + }; + reader.readAsDataURL(file); + } + } + + render() { + const { preview } = this.props; + const { previewSrc } = this.state; + + const headerText = this.props.headerText || 'Photos'; + const headerHint = + this.props.headerHint || 'Add your photos by clicking below'; + const title = this.props.title || 'Select a Photo'; + + const theme = this.props.theme || AmplifyTheme; + const previewStyle = Object.assign({}, PickerPreview, theme.pickerPreview); + + const previewHidden = !(preview && preview !== 'hidden'); + + return ( + + + {I18n.get(headerText)} + + + {previewSrc ? ( + previewHidden ? ( + 'The image has been selected' + ) : ( + + ) + ) : ( + + )} + + + + ); + } } diff --git a/packages/aws-amplify-react/src/Widget/Picker.js b/packages/aws-amplify-react/src/Widget/Picker.js index 88ee2608eb2..36959ad8bfd 100644 --- a/packages/aws-amplify-react/src/Widget/Picker.js +++ b/packages/aws-amplify-react/src/Widget/Picker.js @@ -19,59 +19,59 @@ import AmplifyTheme from '../Amplify-UI/Amplify-UI-Theme'; import { PhotoPickerButton } from '../Amplify-UI/Amplify-UI-Components-React'; const PickerInput = { - width: '100%', - height: '100%', - display: 'inline-block', - position: 'absolute', - left: 0, - top: 0, - opacity: 0, - cursor: 'pointer' + width: '100%', + height: '100%', + display: 'inline-block', + position: 'absolute', + left: 0, + top: 0, + opacity: 0, + cursor: 'pointer', }; const logger = new Logger('Picker'); export default class Picker extends Component { - handleInput(e) { - const that = this; + handleInput(e) { + const that = this; - const file = e.target.files[0]; - if (!file) { return; } + const file = e.target.files[0]; + if (!file) { + return; + } - const { name, size, type } = file; - logger.debug(file); + const { name, size, type } = file; + logger.debug(file); - const { onPick } = this.props; - if (onPick) { - onPick({ - file, - name, - size, - type - }); - } - } + const { onPick } = this.props; + if (onPick) { + onPick({ + file, + name, + size, + type, + }); + } + } - render() { - const title = this.props.title || 'Pick a File'; - const accept = this.props.accept || '*/*'; + render() { + const title = this.props.title || 'Pick a File'; + const accept = this.props.accept || '*/*'; - const theme = this.props.theme || AmplifyTheme; - const inputStyle = Object.assign({}, PickerInput, theme.pickerInput); + const theme = this.props.theme || AmplifyTheme; + const inputStyle = Object.assign({}, PickerInput, theme.pickerInput); - return ( -
- - {I18n.get(title)} - - this.handleInput(e)} - /> -
- ); - } + return ( +
+ {I18n.get(title)} + this.handleInput(e)} + /> +
+ ); + } } diff --git a/packages/aws-amplify-react/src/Widget/SelectMFAType.jsx b/packages/aws-amplify-react/src/Widget/SelectMFAType.jsx index 82820dbff2b..1894f74f91f 100644 --- a/packages/aws-amplify-react/src/Widget/SelectMFAType.jsx +++ b/packages/aws-amplify-react/src/Widget/SelectMFAType.jsx @@ -18,13 +18,13 @@ import Auth from '@aws-amplify/auth'; import AmplifyTheme from '../Amplify-UI/Amplify-UI-Theme'; import { - FormSection, - SectionHeader, - SectionBody, - SectionFooter, - RadioRow, - Button, - Toast, + FormSection, + SectionHeader, + SectionBody, + SectionFooter, + RadioRow, + Button, + Toast, } from '../Amplify-UI/Amplify-UI-Components-React'; import TOTPSetupComp from './TOTPSetupComp'; @@ -32,147 +32,157 @@ import TOTPSetupComp from './TOTPSetupComp'; const logger = new Logger('SelectMFAType'); export default class SelectMFAType extends Component { - constructor(props) { - super(props); - - this.verify = this.verify.bind(this); - this.handleInputChange = this.handleInputChange.bind(this); - - this.state = { - TOTPSetup: false, - selectMessage: null - }; - } - - handleInputChange(evt) { - // clear current state - this.setState({ - TOTPSetup: false, - selectMessage: null - }); - this.inputs = {}; - const { name, value, type, checked } = evt.target; - const check_type = ['radio', 'checkbox'].includes(type); - this.inputs[value] = check_type? checked : value; - } - - verify() { - logger.debug('mfatypes inputs', this.inputs); - if (!this.inputs) { - logger.debug('No mfa type selected'); - return; - } - const { TOTP, SMS, NOMFA } = this.inputs; - let mfaMethod = null; - if (TOTP) { - mfaMethod = 'TOTP'; - } else if (SMS) { - mfaMethod = 'SMS'; - } else if (NOMFA) { - mfaMethod = 'NOMFA'; - } - - const user = this.props.authData; - - if (!Auth || typeof Auth.setPreferredMFA !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - - Auth.setPreferredMFA(user, mfaMethod).then((data) => { - logger.debug('set preferred mfa success', data); - this.setState({ - selectMessage: 'Success! Your MFA Type is now: ' + mfaMethod, - showToast: true - }); - - }).catch(err => { - const { message } = err; - if (message === 'User has not set up software token mfa' - || message === 'User has not verified software token mfa') { - this.setState({ - TOTPSetup: true, - selectMessage: 'You need to setup TOTP', - showToast: true - }); - } - else { - logger.debug('set preferred mfa failed', err); - this.setState({ - selectMessage: 'Failed! You cannot select MFA Type for now!', - showToast: true - }); - } - }); - } - - selectView(theme) { - const { MFATypes } = this.props; - if (!MFATypes || Object.keys(MFATypes).length < 2) { - logger.debug('less than 2 mfa types available'); - return( - - ); - } - const { SMS, TOTP, Optional } = MFATypes; - return ( - - {this.state.showToast && this.state.selectMessage && - this.setState({showToast: false})}> - { I18n.get(this.state.selectMessage) } - - } - {I18n.get('Select MFA Type')} - -
- { SMS? : null - } - { TOTP? : null - } - { Optional? : null - } - -
-
- - - -
- ); - } - - - - render() { - const theme = this.props.theme ? theme: AmplifyTheme; - return ( -
- {this.selectView(theme)} - { this.state.TOTPSetup ? - : null - }
- ); - } + constructor(props) { + super(props); + + this.verify = this.verify.bind(this); + this.handleInputChange = this.handleInputChange.bind(this); + + this.state = { + TOTPSetup: false, + selectMessage: null, + }; + } + + handleInputChange(evt) { + // clear current state + this.setState({ + TOTPSetup: false, + selectMessage: null, + }); + this.inputs = {}; + const { name, value, type, checked } = evt.target; + const check_type = ['radio', 'checkbox'].includes(type); + this.inputs[value] = check_type ? checked : value; + } + + verify() { + logger.debug('mfatypes inputs', this.inputs); + if (!this.inputs) { + logger.debug('No mfa type selected'); + return; + } + const { TOTP, SMS, NOMFA } = this.inputs; + let mfaMethod = null; + if (TOTP) { + mfaMethod = 'TOTP'; + } else if (SMS) { + mfaMethod = 'SMS'; + } else if (NOMFA) { + mfaMethod = 'NOMFA'; + } + + const user = this.props.authData; + + if (!Auth || typeof Auth.setPreferredMFA !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + + Auth.setPreferredMFA(user, mfaMethod) + .then(data => { + logger.debug('set preferred mfa success', data); + this.setState({ + selectMessage: 'Success! Your MFA Type is now: ' + mfaMethod, + showToast: true, + }); + }) + .catch(err => { + const { message } = err; + if ( + message === 'User has not set up software token mfa' || + message === 'User has not verified software token mfa' + ) { + this.setState({ + TOTPSetup: true, + selectMessage: 'You need to setup TOTP', + showToast: true, + }); + } else { + logger.debug('set preferred mfa failed', err); + this.setState({ + selectMessage: 'Failed! You cannot select MFA Type for now!', + showToast: true, + }); + } + }); + } + + selectView(theme) { + const { MFATypes } = this.props; + if (!MFATypes || Object.keys(MFATypes).length < 2) { + logger.debug('less than 2 mfa types available'); + return ( + + ); + } + const { SMS, TOTP, Optional } = MFATypes; + return ( + + {this.state.showToast && this.state.selectMessage && ( + this.setState({ showToast: false })} + > + {I18n.get(this.state.selectMessage)} + + )} + + {I18n.get('Select MFA Type')} + + +
+ {SMS ? ( + + ) : null} + {TOTP ? ( + + ) : null} + {Optional ? ( + + ) : null} +
+
+ + + +
+ ); + } + + render() { + const theme = this.props.theme ? theme : AmplifyTheme; + return ( +
+ {this.selectView(theme)} + {this.state.TOTPSetup ? : null} +
+ ); + } } diff --git a/packages/aws-amplify-react/src/Widget/TOTPSetupComp.jsx b/packages/aws-amplify-react/src/Widget/TOTPSetupComp.jsx index 0537183bb4c..b4ccf6688fe 100644 --- a/packages/aws-amplify-react/src/Widget/TOTPSetupComp.jsx +++ b/packages/aws-amplify-react/src/Widget/TOTPSetupComp.jsx @@ -18,14 +18,14 @@ import Auth from '@aws-amplify/auth'; import AmplifyTheme from '../Amplify-UI/Amplify-UI-Theme'; import { - FormSection, - SectionHeader, - SectionBody, - SectionFooter, - InputLabel, - Input, - Button, - Toast + FormSection, + SectionHeader, + SectionBody, + SectionFooter, + InputLabel, + Input, + Button, + Toast, } from '../Amplify-UI/Amplify-UI-Components-React'; import { totpQrcode } from '@aws-amplify/ui'; @@ -35,122 +35,144 @@ const QRCode = require('qrcode.react'); const logger = new Logger('TOTPSetupComp'); export default class TOTPSetupComp extends Component { - constructor(props) { - super(props); - - this.setup = this.setup.bind(this); - this.showSecretCode = this.showSecretCode.bind(this); - this.verifyTotpToken= this.verifyTotpToken.bind(this); - this.handleInputChange = this.handleInputChange.bind(this); - this.triggerTOTPEvent = this.triggerTOTPEvent.bind(this); - - this.state = { - code: null, - setupMessage: null - }; - } - - componentDidMount() { - this.setup(); - } - - triggerTOTPEvent(event, data, user) { - if (this.props.onTOTPEvent) { - this.props.onTOTPEvent(event, data, user); - } - } - - handleInputChange(evt) { - this.setState({setupMessage: null}); - this.inputs = {}; - const { name, value, type, checked } = evt.target; - const check_type = ['radio', 'checkbox'].includes(type); - this.inputs[name] = check_type? checked : value; - } - - setup() { - this.setState({setupMessage: null}); - const user = this.props.authData; - const issuer = encodeURI(I18n.get('AWSCognito')); - if (!Auth || typeof Auth.setupTOTP !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - - Auth.setupTOTP(user).then((data) => { - logger.debug('secret key', data); - const code = "otpauth://totp/" + issuer + ":" + user.username + "?secret=" + data + "&issuer=" + issuer; - this.setState({code}); - }).catch((err) => logger.debug('totp setup failed', err)); - } - - verifyTotpToken() { - if (!this.inputs) { - logger.debug('no input'); - return; - } - const user = this.props.authData; - const { totpCode } = this.inputs; - if (!Auth || typeof Auth.verifyTotpToken !== 'function' || typeof Auth.setPreferredMFA !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); - } - Auth.verifyTotpToken(user, totpCode) - .then(() => { - // set it to preferred mfa - Auth.setPreferredMFA(user, 'TOTP'); - this.setState({setupMessage: 'Setup TOTP successfully!'}); - logger.debug('set up totp success!'); - this.triggerTOTPEvent('Setup TOTP', 'SUCCESS', user); - }) - .catch(err => { - this.setState({setupMessage: 'Setup TOTP failed!'}); - logger.error(err); - }); - } - - showSecretCode(code, theme) { - if (!code) return null; - return ( -
-
- -
- {I18n.get('Enter Security Code:')} - -
- ); - } - - render() { - const theme = this.props.theme ? this.props.theme: AmplifyTheme; - const code = this.state.code; - - return ( - - {this.state.setupMessage && - - { I18n.get(this.state.setupMessage) } - - } - {I18n.get('Scan then enter verification code')} - - {this.showSecretCode(code, theme)} - {this.state.setupMessage && - I18n.get(this.state.setupMessage) - } - - - - - - - ); - } + constructor(props) { + super(props); + + this.setup = this.setup.bind(this); + this.showSecretCode = this.showSecretCode.bind(this); + this.verifyTotpToken = this.verifyTotpToken.bind(this); + this.handleInputChange = this.handleInputChange.bind(this); + this.triggerTOTPEvent = this.triggerTOTPEvent.bind(this); + + this.state = { + code: null, + setupMessage: null, + }; + } + + componentDidMount() { + this.setup(); + } + + triggerTOTPEvent(event, data, user) { + if (this.props.onTOTPEvent) { + this.props.onTOTPEvent(event, data, user); + } + } + + handleInputChange(evt) { + this.setState({ setupMessage: null }); + this.inputs = {}; + const { name, value, type, checked } = evt.target; + const check_type = ['radio', 'checkbox'].includes(type); + this.inputs[name] = check_type ? checked : value; + } + + setup() { + this.setState({ setupMessage: null }); + const user = this.props.authData; + const issuer = encodeURI(I18n.get('AWSCognito')); + if (!Auth || typeof Auth.setupTOTP !== 'function') { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + + Auth.setupTOTP(user) + .then(data => { + logger.debug('secret key', data); + const code = + 'otpauth://totp/' + + issuer + + ':' + + user.username + + '?secret=' + + data + + '&issuer=' + + issuer; + this.setState({ code }); + }) + .catch(err => logger.debug('totp setup failed', err)); + } + + verifyTotpToken() { + if (!this.inputs) { + logger.debug('no input'); + return; + } + const user = this.props.authData; + const { totpCode } = this.inputs; + if ( + !Auth || + typeof Auth.verifyTotpToken !== 'function' || + typeof Auth.setPreferredMFA !== 'function' + ) { + throw new Error( + 'No Auth module found, please ensure @aws-amplify/auth is imported' + ); + } + Auth.verifyTotpToken(user, totpCode) + .then(() => { + // set it to preferred mfa + Auth.setPreferredMFA(user, 'TOTP'); + this.setState({ setupMessage: 'Setup TOTP successfully!' }); + logger.debug('set up totp success!'); + this.triggerTOTPEvent('Setup TOTP', 'SUCCESS', user); + }) + .catch(err => { + this.setState({ setupMessage: 'Setup TOTP failed!' }); + logger.error(err); + }); + } + + showSecretCode(code, theme) { + if (!code) return null; + return ( +
+
+ +
+ + {I18n.get('Enter Security Code:')} + + +
+ ); + } + + render() { + const theme = this.props.theme ? this.props.theme : AmplifyTheme; + const code = this.state.code; + + return ( + + {this.state.setupMessage && ( + {I18n.get(this.state.setupMessage)} + )} + + {I18n.get('Scan then enter verification code')} + + + {this.showSecretCode(code, theme)} + {this.state.setupMessage && I18n.get(this.state.setupMessage)} + + + + + + + ); + } } diff --git a/packages/aws-amplify-react/src/Widget/TextPicker.js b/packages/aws-amplify-react/src/Widget/TextPicker.js index 9f65ba56a68..13e39c4a98f 100644 --- a/packages/aws-amplify-react/src/Widget/TextPicker.js +++ b/packages/aws-amplify-react/src/Widget/TextPicker.js @@ -18,74 +18,77 @@ import { ConsoleLogger as Logger } from '@aws-amplify/core'; import AmplifyTheme from '../AmplifyTheme'; import Picker from './Picker'; -const Container = { -}; +const Container = {}; const PickerPreview = { - maxWidth: '100%' + maxWidth: '100%', }; const logger = new Logger('TextPicker'); export default class TextPicker extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.handlePick = this.handlePick.bind(this); + this.handlePick = this.handlePick.bind(this); - this.state = { - previewText: props.previewText - }; - } + this.state = { + previewText: props.previewText, + }; + } - handlePick(data) { - const that = this; - const { file, name, size, type } = data; - const { preview, onPick, onLoad } = this.props; + handlePick(data) { + const that = this; + const { file, name, size, type } = data; + const { preview, onPick, onLoad } = this.props; - if (onPick) { onPick(data); } + if (onPick) { + onPick(data); + } - if (preview) { - const reader = new FileReader(); - reader.onload = function(e) { - const text = e.target.result; - that.setState({ previewText: text }); - if (onLoad) { onLoad(text); } - }; - reader.readAsText(file); - } - } + if (preview) { + const reader = new FileReader(); + reader.onload = function(e) { + const text = e.target.result; + that.setState({ previewText: text }); + if (onLoad) { + onLoad(text); + } + }; + reader.readAsText(file); + } + } - render() { - const { preview } = this.props; - const { previewText } = this.state; + render() { + const { preview } = this.props; + const { previewText } = this.state; - const title = this.props.title || 'Pick a File'; + const title = this.props.title || 'Pick a File'; - const theme = this.props.theme || AmplifyTheme; - const containerStyle = Object.assign({}, Container, theme.picker); - const previewStyle = Object.assign( - {}, - PickerPreview, - theme.pickerPreview, - theme.halfHeight, - (preview && preview !== 'hidden')? {} : AmplifyTheme.hidden - ); + const theme = this.props.theme || AmplifyTheme; + const containerStyle = Object.assign({}, Container, theme.picker); + const previewStyle = Object.assign( + {}, + PickerPreview, + theme.pickerPreview, + theme.halfHeight, + preview && preview !== 'hidden' ? {} : AmplifyTheme.hidden + ); - return ( -
- { previewText?
-
{previewText}
-
- : null - } - -
- ); - } + return ( +
+ {previewText ? ( +
+
{previewText}
+
+ ) : null} + +
+ ); + } } diff --git a/packages/aws-amplify-react/src/XR/IconButton.jsx b/packages/aws-amplify-react/src/XR/IconButton.jsx index d9c96272666..5238b744cc4 100644 --- a/packages/aws-amplify-react/src/XR/IconButton.jsx +++ b/packages/aws-amplify-react/src/XR/IconButton.jsx @@ -14,85 +14,133 @@ import * as React from 'react'; import Tooltip from './Tooltip'; import * as AmplifyUI from '@aws-amplify/ui'; -const IconButton = (props) => { - let buttonIcon; - switch(props.variant) { - case "sound-mute": - buttonIcon = ( - - - - - - ); - break; - case "sound": - buttonIcon = ( - - - - - - ); - break; - case "maximize": - buttonIcon = ( - - - - - - ); - break; - case "minimize": - buttonIcon = ( - - - - - - ); - break; - case "enter-vr": - buttonIcon = ( - - - - - - - - ); - break; - case "exit-vr": - buttonIcon = ( - - - - - - - - ); - break; - default: - buttonIcon = null; - break; - } - - return ( - - - - ) -} +const IconButton = props => { + let buttonIcon; + switch (props.variant) { + case 'sound-mute': + buttonIcon = ( + + + + + + ); + break; + case 'sound': + buttonIcon = ( + + + + + + ); + break; + case 'maximize': + buttonIcon = ( + + + + + + ); + break; + case 'minimize': + buttonIcon = ( + + + + + + ); + break; + case 'enter-vr': + buttonIcon = ( + + + + + + + + ); + break; + case 'exit-vr': + buttonIcon = ( + + + + + + + + ); + break; + default: + buttonIcon = null; + break; + } -export default IconButton; \ No newline at end of file + return ( + + + + ); +}; + +export default IconButton; diff --git a/packages/aws-amplify-react/src/XR/Loading.jsx b/packages/aws-amplify-react/src/XR/Loading.jsx index 9c80678d8e2..a73211aa809 100644 --- a/packages/aws-amplify-react/src/XR/Loading.jsx +++ b/packages/aws-amplify-react/src/XR/Loading.jsx @@ -15,36 +15,64 @@ import * as AmplifyUI from '@aws-amplify/ui'; import { sumerianScene } from '../Amplify-UI/data-test-attributes'; -const Loading = (props) => { - return ( -
-
-
- - - - - - - - - -
-
- {props.sceneName} -
- { props.sceneError ? -
{props.sceneError.displayText}
: -
-
-
- } -
-
- ); -} +const Loading = props => { + return ( +
+
+
+ + + + + + + + + +
+
+ {props.sceneName} +
+ {props.sceneError ? ( +
+ {props.sceneError.displayText} +
+ ) : ( +
+
+
+ )} +
+
+ ); +}; export default Loading; diff --git a/packages/aws-amplify-react/src/XR/SumerianScene.jsx b/packages/aws-amplify-react/src/XR/SumerianScene.jsx index b7dc63a926e..92dc164470d 100644 --- a/packages/aws-amplify-react/src/XR/SumerianScene.jsx +++ b/packages/aws-amplify-react/src/XR/SumerianScene.jsx @@ -25,165 +25,255 @@ const SCENE_DOM_ID = 'scene-dom-id'; const logger = new Logger('SumerianScene'); class SumerianScene extends React.Component { - constructor(props) { - super(props); - - this.state = { - showEnableAudio: false, - muted: false, - loading: true, - percentage: 0, - isFullscreen: false, - sceneError: null, - isVRPresentationActive: false - }; - } - - setStateAsync(state) { - return new Promise((resolve) => { - this.setState(state, resolve) - }); - } - - componentDidMount() { - document.addEventListener('fullscreenchange', this.onFullscreenChange.bind(this)); - document.addEventListener('webkitfullscreenchange', this.onFullscreenChange.bind(this)); - document.addEventListener('mozfullscreenchange', this.onFullscreenChange.bind(this)); - document.addEventListener('MSFullscreenChange', this.onFullscreenChange.bind(this)); - - this.loadAndSetupScene(this.props.sceneName, SCENE_DOM_ID) - } - - componentWillUnmount() { - document.removeEventListener('fullscreenchange', this.onFullscreenChange.bind(this)); - document.removeEventListener('webkitfullscreenchange', this.onFullscreenChange.bind(this)); - document.removeEventListener('mozfullscreenchange', this.onFullscreenChange.bind(this)); - document.removeEventListener('MSFullscreenChange', this.onFullscreenChange.bind(this)); - } - - async loadAndSetupScene(sceneName, sceneDomId) { - this.setStateAsync({ loading: true }); - const sceneOptions = { - progressCallback: (progress) => { - const percentage = progress * 100; - this.setState({ percentage }); - } - }; - try { - await XR.loadScene(sceneName, sceneDomId, sceneOptions); - } catch (e) { - const sceneError = { - displayText: 'Failed to load scene', - error: e - } - logger.error(sceneError.displayText, sceneError.error); - this.setStateAsync({sceneError}); - return; - } - - XR.start(sceneName); - - this.setStateAsync({ - muted: XR.isMuted(sceneName), - isVRPresentationActive: XR.isVRPresentationActive(sceneName), - loading: false - }); - - XR.onSceneEvent(sceneName, 'AudioEnabled', () => this.setStateAsync({showEnableAudio: false})); - XR.onSceneEvent(sceneName, 'AudioDisabled', () => this.setStateAsync({showEnableAudio: true})); - } - - setMuted(muted) { - if (this.state.showEnableAudio) { - XR.enableAudio(this.props.sceneName); - this.setState({showEnableAudio: false}); - } - - XR.setMuted(this.props.sceneName, muted); - this.setState({ muted: muted }); - } - - onFullscreenChange() { - const doc = document; - this.setState({ isFullscreen: doc.fullscreenElement !== null }); - } - - async maximize() { - const sceneDomElement = document.getElementById(SCENE_CONTAINER_DOM_ID); - await sceneDomElement.requestFullScreen(); - } - - async minimize() { - const doc = document; - if(doc.exitFullscreen) { - doc.exitFullscreen(); - } else if(doc.mozCancelFullScreen) { - doc.mozCancelFullScreen(); - } else if(doc.webkitExitFullscreen) { - doc.webkitExitFullscreen(); - } - } - - toggleVRPresentation() { - try { - if (this.state.isVRPresentationActive) { - XR.exitVR(this.props.sceneName); - } else { - XR.enterVR(this.props.sceneName); - } - } catch(e) { - logger.error('Unable to start/stop WebVR System: ' + e.message); - return; - } - this.setState({isVRPresentationActive: !this.state.isVRPresentationActive}); - } - - render() { - let muteButton; - let enterOrExitVRButton; - let screenSizeButton; - - if (XR.isSceneLoaded(this.props.sceneName)) { - if (this.state.showEnableAudio) { - muteButton = this.setMuted(false)} autoShowTooltip /> - } else if (XR.isMuted(this.props.sceneName)) { - muteButton = this.setMuted(false)} /> - } else { - muteButton = this.setMuted(true)} /> - } - - if (XR.isVRCapable(this.props.sceneName)) { - if (this.state.isVRPresentationActive) { - logger.info('VR Presentation Active'); - enterOrExitVRButton = this.toggleVRPresentation()} /> - } else { - logger.info('VR Presentation Inactive'); - enterOrExitVRButton = this.toggleVRPresentation()} /> - } - } - - if (this.state.isFullscreen) { - screenSizeButton = this.minimize()} /> - } else { - screenSizeButton = this.maximize()} /> - } - } - - return ( -
-
- {this.state.loading && } -
-
- - {muteButton} - {enterOrExitVRButton} - {screenSizeButton} - -
-
- ); - } + constructor(props) { + super(props); + + this.state = { + showEnableAudio: false, + muted: false, + loading: true, + percentage: 0, + isFullscreen: false, + sceneError: null, + isVRPresentationActive: false, + }; + } + + setStateAsync(state) { + return new Promise(resolve => { + this.setState(state, resolve); + }); + } + + componentDidMount() { + document.addEventListener( + 'fullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.addEventListener( + 'webkitfullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.addEventListener( + 'mozfullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.addEventListener( + 'MSFullscreenChange', + this.onFullscreenChange.bind(this) + ); + + this.loadAndSetupScene(this.props.sceneName, SCENE_DOM_ID); + } + + componentWillUnmount() { + document.removeEventListener( + 'fullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.removeEventListener( + 'webkitfullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.removeEventListener( + 'mozfullscreenchange', + this.onFullscreenChange.bind(this) + ); + document.removeEventListener( + 'MSFullscreenChange', + this.onFullscreenChange.bind(this) + ); + } + + async loadAndSetupScene(sceneName, sceneDomId) { + this.setStateAsync({ loading: true }); + const sceneOptions = { + progressCallback: progress => { + const percentage = progress * 100; + this.setState({ percentage }); + }, + }; + try { + await XR.loadScene(sceneName, sceneDomId, sceneOptions); + } catch (e) { + const sceneError = { + displayText: 'Failed to load scene', + error: e, + }; + logger.error(sceneError.displayText, sceneError.error); + this.setStateAsync({ sceneError }); + return; + } + + XR.start(sceneName); + + this.setStateAsync({ + muted: XR.isMuted(sceneName), + isVRPresentationActive: XR.isVRPresentationActive(sceneName), + loading: false, + }); + + XR.onSceneEvent(sceneName, 'AudioEnabled', () => + this.setStateAsync({ showEnableAudio: false }) + ); + XR.onSceneEvent(sceneName, 'AudioDisabled', () => + this.setStateAsync({ showEnableAudio: true }) + ); + } + + setMuted(muted) { + if (this.state.showEnableAudio) { + XR.enableAudio(this.props.sceneName); + this.setState({ showEnableAudio: false }); + } + + XR.setMuted(this.props.sceneName, muted); + this.setState({ muted: muted }); + } + + onFullscreenChange() { + const doc = document; + this.setState({ isFullscreen: doc.fullscreenElement !== null }); + } + + async maximize() { + const sceneDomElement = document.getElementById(SCENE_CONTAINER_DOM_ID); + await sceneDomElement.requestFullScreen(); + } + + async minimize() { + const doc = document; + if (doc.exitFullscreen) { + doc.exitFullscreen(); + } else if (doc.mozCancelFullScreen) { + doc.mozCancelFullScreen(); + } else if (doc.webkitExitFullscreen) { + doc.webkitExitFullscreen(); + } + } + + toggleVRPresentation() { + try { + if (this.state.isVRPresentationActive) { + XR.exitVR(this.props.sceneName); + } else { + XR.enterVR(this.props.sceneName); + } + } catch (e) { + logger.error('Unable to start/stop WebVR System: ' + e.message); + return; + } + this.setState({ + isVRPresentationActive: !this.state.isVRPresentationActive, + }); + } + + render() { + let muteButton; + let enterOrExitVRButton; + let screenSizeButton; + + if (XR.isSceneLoaded(this.props.sceneName)) { + if (this.state.showEnableAudio) { + muteButton = ( + this.setMuted(false)} + autoShowTooltip + /> + ); + } else if (XR.isMuted(this.props.sceneName)) { + muteButton = ( + this.setMuted(false)} + /> + ); + } else { + muteButton = ( + this.setMuted(true)} + /> + ); + } + + if (XR.isVRCapable(this.props.sceneName)) { + if (this.state.isVRPresentationActive) { + logger.info('VR Presentation Active'); + enterOrExitVRButton = ( + this.toggleVRPresentation()} + /> + ); + } else { + logger.info('VR Presentation Inactive'); + enterOrExitVRButton = ( + this.toggleVRPresentation()} + /> + ); + } + } + + if (this.state.isFullscreen) { + screenSizeButton = ( + this.minimize()} + /> + ); + } else { + screenSizeButton = ( + this.maximize()} + /> + ); + } + } + + return ( +
+
+ {this.state.loading && ( + + )} +
+
+ + {muteButton} + {enterOrExitVRButton} + {screenSizeButton} + +
+
+ ); + } } export default SumerianScene; diff --git a/packages/aws-amplify-react/src/XR/Tooltip.jsx b/packages/aws-amplify-react/src/XR/Tooltip.jsx index 5f3a7ea0ccc..fc1d43361dd 100644 --- a/packages/aws-amplify-react/src/XR/Tooltip.jsx +++ b/packages/aws-amplify-react/src/XR/Tooltip.jsx @@ -13,18 +13,18 @@ import * as React from 'react'; import * as AmplifyUI from '@aws-amplify/ui'; -const Tooltip = (props) => { - let classes = `${AmplifyUI.tooltip}`; - - if (props.autoShowTooltip) { - classes = `${AmplifyUI.tooltip} ${AmplifyUI.autoShowTooltip}`; - } +const Tooltip = props => { + let classes = `${AmplifyUI.tooltip}`; - return ( -
- {props.children} -
- ) -} + if (props.autoShowTooltip) { + classes = `${AmplifyUI.tooltip} ${AmplifyUI.autoShowTooltip}`; + } -export default Tooltip; \ No newline at end of file + return ( +
+ {props.children} +
+ ); +}; + +export default Tooltip; diff --git a/packages/aws-amplify-react/src/XR/index.jsx b/packages/aws-amplify-react/src/XR/index.jsx index 63e61ae222a..b6b0038f7fd 100644 --- a/packages/aws-amplify-react/src/XR/index.jsx +++ b/packages/aws-amplify-react/src/XR/index.jsx @@ -10,4 +10,4 @@ * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ -export { default as SumerianScene } from './SumerianScene'; \ No newline at end of file +export { default as SumerianScene } from './SumerianScene'; diff --git a/packages/aws-amplify-react/tslint.json b/packages/aws-amplify-react/tslint.json index 7659e729e55..1bb9e144d24 100644 --- a/packages/aws-amplify-react/tslint.json +++ b/packages/aws-amplify-react/tslint.json @@ -1,72 +1,45 @@ - { - "defaultSeverity": "error", - "plugins": [ - "prettier" - ], - "extends": [ - //"tslint-config-airbnb" - ], - "jsRules": {}, - "rules": { - "prefer-const": true, - "max-line-length": [true, 120], - "no-empty-interface": true, - "no-var-keyword": true, - "object-literal-shorthand": true, - "no-eval": true, - "space-before-function-paren": [ - true, - { - "anonymous": "never", - "named": "never" - } - ], - "no-parameter-reassignment": true, - "align": [ - true, - "arguments", - "parameters" - ], - "no-duplicate-imports": false, - "one-variable-per-declaration": [ - false, - "ignore-for-loop" - ], - "triple-equals": [ - true, - "allow-null-check" - ], - "no-boolean-literal-compare": true, - "comment-format": [ - true, - "check-space" - ], - "indent": [ - true, - "spaces", - 2 - ], - "whitespace": [ - false, - "check-branch", - "check-decl", - "check-operator", - "check-preblock" - ], - "eofline": true, - "variable-name": [ - true, - "check-format", // 22.2 - "allow-pascal-case", - "allow-snake-case", - "allow-leading-underscore" - ], - "semicolon": [ - true, - "always", - "ignore-interfaces" - ] - }, - "rulesDirectory": [] -} \ No newline at end of file + "defaultSeverity": "error", + "plugins": ["prettier"], + "extends": [], + "jsRules": {}, + "rules": { + "prefer-const": true, + "max-line-length": [true, 120], + "no-empty-interface": true, + "no-var-keyword": true, + "object-literal-shorthand": true, + "no-eval": true, + "space-before-function-paren": [ + true, + { + "anonymous": "never", + "named": "never" + } + ], + "no-parameter-reassignment": true, + "align": [true, "parameters"], + "no-duplicate-imports": true, + "one-variable-per-declaration": [false, "ignore-for-loop"], + "triple-equals": [true, "allow-null-check"], + "comment-format": [true, "check-space"], + "indent": [false], + "whitespace": [ + false, + "check-branch", + "check-decl", + "check-operator", + "check-preblock" + ], + "eofline": true, + "variable-name": [ + true, + "check-format", + "allow-pascal-case", + "allow-snake-case", + "allow-leading-underscore" + ], + "semicolon": [true, "always", "ignore-interfaces"] + }, + "rulesDirectory": [] +} diff --git a/packages/aws-amplify-vue/CHANGELOG.md b/packages/aws-amplify-vue/CHANGELOG.md index 041cb06c619..2c1c3da8448 100644 --- a/packages/aws-amplify-vue/CHANGELOG.md +++ b/packages/aws-amplify-vue/CHANGELOG.md @@ -7,636 +7,483 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package aws-amplify-vue - - - - ## [0.2.14](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.13...aws-amplify-vue@0.2.14) (2019-07-30) **Note:** Version bump only for package aws-amplify-vue - - - - -## [0.2.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.13-unstable.0...aws-amplify-vue@0.2.13) (2019-07-09) - - +## [0.2.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.13-unstable.0...aws-amplify-vue@0.2.13) (2019-07-09) **Note:** Version bump only for package aws-amplify-vue -## [0.2.13-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.12...aws-amplify-vue@0.2.13-unstable.0) (2019-07-09) - - +## [0.2.13-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.12...aws-amplify-vue@0.2.13-unstable.0) (2019-07-09) **Note:** Version bump only for package aws-amplify-vue -## [0.2.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.12-unstable.3...aws-amplify-vue@0.2.12) (2019-06-17) - - +## [0.2.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.12-unstable.3...aws-amplify-vue@0.2.12) (2019-06-17) **Note:** Version bump only for package aws-amplify-vue -## [0.2.12-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.12-unstable.2...aws-amplify-vue@0.2.12-unstable.3) (2019-06-06) - - +## [0.2.12-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.12-unstable.2...aws-amplify-vue@0.2.12-unstable.3) (2019-06-06) **Note:** Version bump only for package aws-amplify-vue -## [0.2.12-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.12-unstable.1...aws-amplify-vue@0.2.12-unstable.2) (2019-05-31) +## [0.2.12-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.12-unstable.1...aws-amplify-vue@0.2.12-unstable.2) (2019-05-31) ### Bug Fixes -* **aws-amplify-vue:** remove unused variable ([#3303](https://github.com/aws-amplify/amplify-js/issues/3303)) ([4512d0d](https://github.com/aws-amplify/amplify-js/commit/4512d0d)) - - - +- **aws-amplify-vue:** remove unused variable ([#3303](https://github.com/aws-amplify/amplify-js/issues/3303)) ([4512d0d](https://github.com/aws-amplify/amplify-js/commit/4512d0d)) -## [0.2.12-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.12-unstable.0...aws-amplify-vue@0.2.12-unstable.1) (2019-05-24) +## [0.2.12-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.12-unstable.0...aws-amplify-vue@0.2.12-unstable.1) (2019-05-24) ### Bug Fixes -* **@aws-amplify-vue/auth:** exception in QrcodeVue because of invalid parameter type ([#2656](https://github.com/aws-amplify/amplify-js/issues/2656)) ([1dead96](https://github.com/aws-amplify/amplify-js/commit/1dead96)) - - - +- **@aws-amplify-vue/auth:** exception in QrcodeVue because of invalid parameter type ([#2656](https://github.com/aws-amplify/amplify-js/issues/2656)) ([1dead96](https://github.com/aws-amplify/amplify-js/commit/1dead96)) -## [0.2.12-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.11...aws-amplify-vue@0.2.12-unstable.0) (2019-05-24) - - +## [0.2.12-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.11...aws-amplify-vue@0.2.12-unstable.0) (2019-05-24) **Note:** Version bump only for package aws-amplify-vue -## [0.2.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.11-unstable.1...aws-amplify-vue@0.2.11) (2019-05-14) - - +## [0.2.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.11-unstable.1...aws-amplify-vue@0.2.11) (2019-05-14) **Note:** Version bump only for package aws-amplify-vue -## [0.2.11-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.11-unstable.0...aws-amplify-vue@0.2.11-unstable.1) (2019-05-13) +## [0.2.11-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.11-unstable.0...aws-amplify-vue@0.2.11-unstable.1) (2019-05-13) ### Bug Fixes -* add a todo to the greeting object in order to adjust the Angular Greeting Component to match React, fix typo in requireNewPassword ([49eae14](https://github.com/aws-amplify/amplify-js/commit/49eae14)) - - - +- add a todo to the greeting object in order to adjust the Angular Greeting Component to match React, fix typo in requireNewPassword ([49eae14](https://github.com/aws-amplify/amplify-js/commit/49eae14)) -## [0.2.11-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.10...aws-amplify-vue@0.2.11-unstable.0) (2019-05-09) +## [0.2.11-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.10...aws-amplify-vue@0.2.11-unstable.0) (2019-05-09) ### Bug Fixes -* **Vue-SignUp:** check fields are non-empty prior to submitting them ([1a4d04a](https://github.com/aws-amplify/amplify-js/commit/1a4d04a)), closes [#3174](https://github.com/aws-amplify/amplify-js/issues/3174) - - - +- **Vue-SignUp:** check fields are non-empty prior to submitting them ([1a4d04a](https://github.com/aws-amplify/amplify-js/commit/1a4d04a)), closes [#3174](https://github.com/aws-amplify/amplify-js/issues/3174) -## [0.2.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.10-unstable.1...aws-amplify-vue@0.2.10) (2019-05-06) - - +## [0.2.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.10-unstable.1...aws-amplify-vue@0.2.10) (2019-05-06) **Note:** Version bump only for package aws-amplify-vue -## [0.2.10-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.10-unstable.0...aws-amplify-vue@0.2.10-unstable.1) (2019-04-26) - - +## [0.2.10-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.10-unstable.0...aws-amplify-vue@0.2.10-unstable.1) (2019-04-26) **Note:** Version bump only for package aws-amplify-vue -## [0.2.10-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.9...aws-amplify-vue@0.2.10-unstable.0) (2019-04-26) - - +## [0.2.10-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.9...aws-amplify-vue@0.2.10-unstable.0) (2019-04-26) **Note:** Version bump only for package aws-amplify-vue -## [0.2.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.9-unstable.0...aws-amplify-vue@0.2.9) (2019-04-04) - - +## [0.2.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.9-unstable.0...aws-amplify-vue@0.2.9) (2019-04-04) **Note:** Version bump only for package aws-amplify-vue -## [0.2.9-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.8...aws-amplify-vue@0.2.9-unstable.0) (2019-04-02) +## [0.2.9-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.8...aws-amplify-vue@0.2.9-unstable.0) (2019-04-02) ### Bug Fixes -* **aws-amplify-vue:** Change the event name to signIn ([e555536](https://github.com/aws-amplify/amplify-js/commit/e555536)) - - - +- **aws-amplify-vue:** Change the event name to signIn ([e555536](https://github.com/aws-amplify/amplify-js/commit/e555536)) -## [0.2.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.8-unstable.0...aws-amplify-vue@0.2.8) (2019-03-28) - - +## [0.2.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.8-unstable.0...aws-amplify-vue@0.2.8) (2019-03-28) **Note:** Version bump only for package aws-amplify-vue -## [0.2.8-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.7...aws-amplify-vue@0.2.8-unstable.0) (2019-03-11) +## [0.2.8-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.7...aws-amplify-vue@0.2.8-unstable.0) (2019-03-11) ### Bug Fixes -* **aws-amplify-vue/storage:** Fixed PhotoPicker input element not using the given accept attribute ([f2f8240](https://github.com/aws-amplify/amplify-js/commit/f2f8240)) - - - +- **aws-amplify-vue/storage:** Fixed PhotoPicker input element not using the given accept attribute ([f2f8240](https://github.com/aws-amplify/amplify-js/commit/f2f8240)) -## [0.2.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.7-unstable.0...aws-amplify-vue@0.2.7) (2019-03-06) - - +## [0.2.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.7-unstable.0...aws-amplify-vue@0.2.7) (2019-03-06) **Note:** Version bump only for package aws-amplify-vue -## [0.2.7-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6...aws-amplify-vue@0.2.7-unstable.0) (2019-03-05) +## [0.2.7-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6...aws-amplify-vue@0.2.7-unstable.0) (2019-03-05) ### Bug Fixes -* **@aws-amplify/aws-amplify-vue:** Access the 'key' property of the 'signUpField' object to avoid a [objec Object] value in the HTML ([fb98183](https://github.com/aws-amplify/amplify-js/commit/fb98183)) -* **@aws-amplify/aws-amplify-vue:** Change the 'type' property values taken from the 'username' and 'email' objects in the signUpFields array so that they are valid HTML attribute values. ([8c28cae](https://github.com/aws-amplify/amplify-js/commit/8c28cae)) -* **@aws-amplify/aws-amplify-vue:** Change the tests to check for the HTML valid attribute value 'text' rather than 'string' ([5f982e1](https://github.com/aws-amplify/amplify-js/commit/5f982e1)) - - - +- **@aws-amplify/aws-amplify-vue:** Access the 'key' property of the 'signUpField' object to avoid a [objec Object] value in the HTML ([fb98183](https://github.com/aws-amplify/amplify-js/commit/fb98183)) +- **@aws-amplify/aws-amplify-vue:** Change the 'type' property values taken from the 'username' and 'email' objects in the signUpFields array so that they are valid HTML attribute values. ([8c28cae](https://github.com/aws-amplify/amplify-js/commit/8c28cae)) +- **@aws-amplify/aws-amplify-vue:** Change the tests to check for the HTML valid attribute value 'text' rather than 'string' ([5f982e1](https://github.com/aws-amplify/amplify-js/commit/5f982e1)) -## [0.2.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.5...aws-amplify-vue@0.2.6) (2019-03-04) - - +## [0.2.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.5...aws-amplify-vue@0.2.6) (2019-03-04) **Note:** Version bump only for package aws-amplify-vue -## [0.2.6-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.4...aws-amplify-vue@0.2.6-unstable.5) (2019-02-27) - - +## [0.2.6-unstable.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.4...aws-amplify-vue@0.2.6-unstable.5) (2019-02-27) **Note:** Version bump only for package aws-amplify-vue -## [0.2.6-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.3...aws-amplify-vue@0.2.6-unstable.4) (2019-02-18) - - +## [0.2.6-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.3...aws-amplify-vue@0.2.6-unstable.4) (2019-02-18) **Note:** Version bump only for package aws-amplify-vue -## [0.2.6-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.2...aws-amplify-vue@0.2.6-unstable.3) (2019-02-11) - - +## [0.2.6-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.2...aws-amplify-vue@0.2.6-unstable.3) (2019-02-11) **Note:** Version bump only for package aws-amplify-vue -## [0.2.6-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.1...aws-amplify-vue@0.2.6-unstable.2) (2019-01-23) - - +## [0.2.6-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.1...aws-amplify-vue@0.2.6-unstable.2) (2019-01-23) **Note:** Version bump only for package aws-amplify-vue -## [0.2.6-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.0...aws-amplify-vue@0.2.6-unstable.1) (2019-01-18) - - +## [0.2.6-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.6-unstable.0...aws-amplify-vue@0.2.6-unstable.1) (2019-01-18) **Note:** Version bump only for package aws-amplify-vue -## [0.2.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.5...aws-amplify-vue@0.2.6-unstable.0) (2019-01-16) - - +## [0.2.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.5...aws-amplify-vue@0.2.6-unstable.0) (2019-01-16) **Note:** Version bump only for package aws-amplify-vue -## [0.2.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.5-unstable.0...aws-amplify-vue@0.2.5) (2018-12-26) - - +## [0.2.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.5-unstable.0...aws-amplify-vue@0.2.5) (2018-12-26) **Note:** Version bump only for package aws-amplify-vue -## [0.2.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.4...aws-amplify-vue@0.2.5-unstable.0) (2018-12-17) - - +## [0.2.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.4...aws-amplify-vue@0.2.5-unstable.0) (2018-12-17) **Note:** Version bump only for package aws-amplify-vue -## [0.2.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.3-unstable.2...aws-amplify-vue@0.2.4) (2018-12-15) - - +## [0.2.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.3-unstable.2...aws-amplify-vue@0.2.4) (2018-12-15) **Note:** Version bump only for package aws-amplify-vue + ## [0.2.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.2...aws-amplify-vue@0.2.3) (2018-12-14) -## [0.2.3-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.3-unstable.1...aws-amplify-vue@0.2.3-unstable.2) (2018-12-14) - - +## [0.2.3-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.3-unstable.1...aws-amplify-vue@0.2.3-unstable.2) (2018-12-14) **Note:** Version bump only for package aws-amplify-vue -## [0.2.3-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.3-unstable.0...aws-amplify-vue@0.2.3-unstable.1) (2018-12-14) - - +## [0.2.3-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.3-unstable.0...aws-amplify-vue@0.2.3-unstable.1) (2018-12-14) **Note:** Version bump only for package aws-amplify-vue -## [0.2.3-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.2...aws-amplify-vue@0.2.3-unstable.0) (2018-12-14) - - - +## [0.2.3-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.2...aws-amplify-vue@0.2.3-unstable.0) (2018-12-14) **Note:** Version bump only for package aws-amplify-vue -## [0.2.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.2-unstable.0...aws-amplify-vue@0.2.2) (2018-12-14) - - +## [0.2.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.2-unstable.0...aws-amplify-vue@0.2.2) (2018-12-14) **Note:** Version bump only for package aws-amplify-vue -## [0.2.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.1...aws-amplify-vue@0.2.2-unstable.0) (2018-12-13) +## [0.2.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.1...aws-amplify-vue@0.2.2-unstable.0) (2018-12-13) ### Features -* **@aws-amplify/interactions @aws-amplify/react @aws-amplify/react-native @aws-amplify/angular @aws-amplify/vue:** Update interactions to include voice ([#2121](https://github.com/aws-amplify/amplify-js/issues/2121)) ([938d2a5](https://github.com/aws-amplify/amplify-js/commit/938d2a5)) - - - +- **@aws-amplify/interactions @aws-amplify/react @aws-amplify/react-native @aws-amplify/angular @aws-amplify/vue:** Update interactions to include voice ([#2121](https://github.com/aws-amplify/amplify-js/issues/2121)) ([938d2a5](https://github.com/aws-amplify/amplify-js/commit/938d2a5)) -## [0.2.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.1-unstable.1...aws-amplify-vue@0.2.1) (2018-12-13) - - +## [0.2.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.1-unstable.1...aws-amplify-vue@0.2.1) (2018-12-13) **Note:** Version bump only for package aws-amplify-vue -## [0.2.1-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.1-unstable.0...aws-amplify-vue@0.2.1-unstable.1) (2018-12-11) +## [0.2.1-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.1-unstable.0...aws-amplify-vue@0.2.1-unstable.1) (2018-12-11) ### Features -* **@aws-amplify/auth:** Add signInConfig.isSignUpDisplayed - fix tests ([aaa3b40](https://github.com/aws-amplify/amplify-js/commit/aaa3b40)) -* **@aws-amplify/auth:** Add signInConfig.isSignUpDisplayed attribut ([aa271ea](https://github.com/aws-amplify/amplify-js/commit/aa271ea)) - - - +- **@aws-amplify/auth:** Add signInConfig.isSignUpDisplayed - fix tests ([aaa3b40](https://github.com/aws-amplify/amplify-js/commit/aaa3b40)) +- **@aws-amplify/auth:** Add signInConfig.isSignUpDisplayed attribut ([aa271ea](https://github.com/aws-amplify/amplify-js/commit/aa271ea)) -## [0.2.1-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.11-unstable.0...aws-amplify-vue@0.2.1-unstable.0) (2018-12-10) - - +## [0.2.1-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.11-unstable.0...aws-amplify-vue@0.2.1-unstable.0) (2018-12-10) **Note:** Version bump only for package aws-amplify-vue -## [0.1.11-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.10...aws-amplify-vue@0.1.11-unstable.0) (2018-12-07) - - +## [0.1.11-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.10...aws-amplify-vue@0.1.11-unstable.0) (2018-12-07) **Note:** Version bump only for package aws-amplify-vue -## [0.1.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.9...aws-amplify-vue@0.1.10) (2018-12-07) - - +## [0.1.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.9...aws-amplify-vue@0.1.10) (2018-12-07) **Note:** Version bump only for package aws-amplify-vue -## [0.1.10-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.10-unstable.1...aws-amplify-vue@0.1.10-unstable.2) (2018-12-06) - - +## [0.1.10-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.10-unstable.1...aws-amplify-vue@0.1.10-unstable.2) (2018-12-06) **Note:** Version bump only for package aws-amplify-vue -## [0.1.10-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.10-unstable.0...aws-amplify-vue@0.1.10-unstable.1) (2018-12-06) - - +## [0.1.10-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.10-unstable.0...aws-amplify-vue@0.1.10-unstable.1) (2018-12-06) **Note:** Version bump only for package aws-amplify-vue -## [0.1.10-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.9...aws-amplify-vue@0.1.10-unstable.0) (2018-12-06) - - +## [0.1.10-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.9...aws-amplify-vue@0.1.10-unstable.0) (2018-12-06) **Note:** Version bump only for package aws-amplify-vue -## [0.1.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8...aws-amplify-vue@0.1.9) (2018-12-06) - - +## [0.1.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8...aws-amplify-vue@0.1.9) (2018-12-06) **Note:** Version bump only for package aws-amplify-vue -## [0.1.9-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8...aws-amplify-vue@0.1.9-unstable.0) (2018-12-05) - - +## [0.1.9-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8...aws-amplify-vue@0.1.9-unstable.0) (2018-12-05) **Note:** Version bump only for package aws-amplify-vue -## [0.1.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8-unstable.4...aws-amplify-vue@0.1.8) (2018-12-03) - - +## [0.1.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8-unstable.4...aws-amplify-vue@0.1.8) (2018-12-03) **Note:** Version bump only for package aws-amplify-vue -## [0.1.8-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8-unstable.3...aws-amplify-vue@0.1.8-unstable.4) (2018-11-30) - +## [0.1.8-unstable.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8-unstable.3...aws-amplify-vue@0.1.8-unstable.4) (2018-11-30) **Note:** Version bump only for package aws-amplify-vue -## [0.1.8-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8-unstable.2...aws-amplify-vue@0.1.8-unstable.3) (2018-11-30) - +## [0.1.8-unstable.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8-unstable.2...aws-amplify-vue@0.1.8-unstable.3) (2018-11-30) **Note:** Version bump only for package aws-amplify-vue -## [0.1.8-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8-unstable.1...aws-amplify-vue@0.1.8-unstable.2) (2018-11-26) - +## [0.1.8-unstable.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8-unstable.1...aws-amplify-vue@0.1.8-unstable.2) (2018-11-26) **Note:** Version bump only for package aws-amplify-vue -## [0.1.8-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8-unstable.0...aws-amplify-vue@0.1.8-unstable.1) (2018-11-21) - +## [0.1.8-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.8-unstable.0...aws-amplify-vue@0.1.8-unstable.1) (2018-11-21) **Note:** Version bump only for package aws-amplify-vue -## [0.1.8-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.7...aws-amplify-vue@0.1.8-unstable.0) (2018-11-19) - +## [0.1.8-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.7...aws-amplify-vue@0.1.8-unstable.0) (2018-11-19) **Note:** Version bump only for package aws-amplify-vue -## [0.2.1-beta.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.1-beta.2...aws-amplify-vue@0.2.1-beta.3) (2018-11-19) +## [0.2.1-beta.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.1-beta.2...aws-amplify-vue@0.2.1-beta.3) (2018-11-19) **Note:** Version bump only for package aws-amplify-vue -## [0.2.1-beta.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.1-beta.1...aws-amplify-vue@0.2.1-beta.2) (2018-11-14) +## [0.2.1-beta.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.2.1-beta.1...aws-amplify-vue@0.2.1-beta.2) (2018-11-14) **Note:** Version bump only for package aws-amplify-vue -## [0.2.1-beta.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.7-unstable.1...aws-amplify-vue@0.2.1-beta.1) (2018-11-14) - +## [0.2.1-beta.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.7-unstable.1...aws-amplify-vue@0.2.1-beta.1) (2018-11-14) **Note:** Version bump only for package aws-amplify-vue -## [0.1.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.7-unstable.1...aws-amplify-vue@0.1.7) (2018-11-12) - +## [0.1.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.7-unstable.1...aws-amplify-vue@0.1.7) (2018-11-12) **Note:** Version bump only for package aws-amplify-vue -## [0.1.7-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.7-unstable.0...aws-amplify-vue@0.1.7-unstable.1) (2018-11-09) - - +## [0.1.7-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.7-unstable.0...aws-amplify-vue@0.1.7-unstable.1) (2018-11-09) **Note:** Version bump only for package aws-amplify-vue -## [0.1.7-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.6...aws-amplify-vue@0.1.7-unstable.0) (2018-11-07) - +## [0.1.7-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.6...aws-amplify-vue@0.1.7-unstable.0) (2018-11-07) **Note:** Version bump only for package aws-amplify-vue -## [0.2.1-beta.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.6-unstable.0...aws-amplify-vue@0.2.1-beta.0) (2018-11-02) - +## [0.2.1-beta.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.6-unstable.0...aws-amplify-vue@0.2.1-beta.0) (2018-11-02) **Note:** Version bump only for package aws-amplify-vue -## [0.1.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.6-unstable.0...aws-amplify-vue@0.1.6) (2018-11-01) +## [0.1.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.6-unstable.0...aws-amplify-vue@0.1.6) (2018-11-01) **Note:** Version bump only for package aws-amplify-vue -## [0.1.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.5...aws-amplify-vue@0.1.6-unstable.0) (2018-10-30) - - +## [0.1.6-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.5...aws-amplify-vue@0.1.6-unstable.0) (2018-10-30) **Note:** Version bump only for package aws-amplify-vue -## [0.1.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.5-unstable.1...aws-amplify-vue@0.1.5) (2018-10-29) - - +## [0.1.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.5-unstable.1...aws-amplify-vue@0.1.5) (2018-10-29) **Note:** Version bump only for package aws-amplify-vue -## [0.1.5-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.5-unstable.0...aws-amplify-vue@0.1.5-unstable.1) (2018-10-29) - - +## [0.1.5-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.5-unstable.0...aws-amplify-vue@0.1.5-unstable.1) (2018-10-29) **Note:** Version bump only for package aws-amplify-vue -## [0.1.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.4...aws-amplify-vue@0.1.5-unstable.0) (2018-10-24) +## [0.1.5-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.4...aws-amplify-vue@0.1.5-unstable.0) (2018-10-24) ### Features -* **aws-amplify-vue:** add Connect component ([ae3ac0a](https://github.com/aws-amplify/amplify-js/commit/ae3ac0a)) - - - +- **aws-amplify-vue:** add Connect component ([ae3ac0a](https://github.com/aws-amplify/amplify-js/commit/ae3ac0a)) -## [0.1.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.4-unstable.1...aws-amplify-vue@0.1.4) (2018-10-17) - - +## [0.1.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.4-unstable.1...aws-amplify-vue@0.1.4) (2018-10-17) **Note:** Version bump only for package aws-amplify-vue -## [0.1.4-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.4-unstable.0...aws-amplify-vue@0.1.4-unstable.1) (2018-10-10) - - +## [0.1.4-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.4-unstable.0...aws-amplify-vue@0.1.4-unstable.1) (2018-10-10) **Note:** Version bump only for package aws-amplify-vue -## [0.1.4-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.3-unstable.1...aws-amplify-vue@0.1.4-unstable.0) (2018-10-05) - - +## [0.1.4-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.3-unstable.1...aws-amplify-vue@0.1.4-unstable.0) (2018-10-05) **Note:** Version bump only for package aws-amplify-vue -## [0.1.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.3-unstable.1...aws-amplify-vue@0.1.3) (2018-10-04) - - +## [0.1.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.3-unstable.1...aws-amplify-vue@0.1.3) (2018-10-04) **Note:** Version bump only for package aws-amplify-vue -## [0.1.3-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.3-unstable.0...aws-amplify-vue@0.1.3-unstable.1) (2018-10-03) - - +## [0.1.3-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.3-unstable.0...aws-amplify-vue@0.1.3-unstable.1) (2018-10-03) **Note:** Version bump only for package aws-amplify-vue -## [0.1.3-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.2-unstable.1...aws-amplify-vue@0.1.3-unstable.0) (2018-10-03) - - +## [0.1.3-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.2-unstable.1...aws-amplify-vue@0.1.3-unstable.0) (2018-10-03) **Note:** Version bump only for package aws-amplify-vue -## [0.1.2](https://github.com/powerful23/aws-amplify/compare/aws-amplify-vue@0.1.2-unstable.1...aws-amplify-vue@0.1.2) (2018-10-03) - - +## [0.1.2](https://github.com/powerful23/aws-amplify/compare/aws-amplify-vue@0.1.2-unstable.1...aws-amplify-vue@0.1.2) (2018-10-03) **Note:** Version bump only for package aws-amplify-vue -## [0.1.2-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.2-unstable.0...aws-amplify-vue@0.1.2-unstable.1) (2018-10-02) - - +## [0.1.2-unstable.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.2-unstable.0...aws-amplify-vue@0.1.2-unstable.1) (2018-10-02) **Note:** Version bump only for package aws-amplify-vue -## [0.1.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.1...aws-amplify-vue@0.1.2-unstable.0) (2018-10-01) - - +## [0.1.2-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.1...aws-amplify-vue@0.1.2-unstable.0) (2018-10-01) **Note:** Version bump only for package aws-amplify-vue -## [0.1.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.1-unstable.0...aws-amplify-vue@0.1.1) (2018-09-27) - - +## [0.1.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.1-unstable.0...aws-amplify-vue@0.1.1) (2018-09-27) **Note:** Version bump only for package aws-amplify-vue -## [0.1.1-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.1-beta.1...aws-amplify-vue@0.1.1-unstable.0) (2018-09-26) - - +## [0.1.1-unstable.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.1-beta.1...aws-amplify-vue@0.1.1-unstable.0) (2018-09-26) **Note:** Version bump only for package aws-amplify-vue -## [0.1.1-beta.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.1-beta.0...aws-amplify-vue@0.1.1-beta.1) (2018-09-12) - - +## [0.1.1-beta.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-vue@0.1.1-beta.0...aws-amplify-vue@0.1.1-beta.1) (2018-09-12) **Note:** Version bump only for package aws-amplify-vue -## 0.1.1-beta.0 (2018-09-12) - - +## 0.1.1-beta.0 (2018-09-12) **Note:** Version bump only for package aws-amplify-vue diff --git a/packages/aws-amplify-vue/README.md b/packages/aws-amplify-vue/README.md index 8086e3f2fb6..dca6a0b8f58 100644 --- a/packages/aws-amplify-vue/README.md +++ b/packages/aws-amplify-vue/README.md @@ -1,10 +1,10 @@ # AWS Amplify Package - aws-amplify-vue -The ```aws-amplify-vue``` package is a set of Vue components which integrates your Vue application with the AWS-Amplify library. +The `aws-amplify-vue` package is a set of Vue components which integrates your Vue application with the AWS-Amplify library. It is intended for use with Vue applications using version 2.5 or above, and was created using the Vue 3.0 CLI. -## Setup +## Setup In your Vue app, install the following: @@ -37,7 +37,7 @@ In App.vue: import { components } from 'aws-amplify-vue' export default { - name: 'app', + name: 'app', components: { ..., ...components @@ -49,14 +49,16 @@ export default { ## AmplifyEventBus -The aws-amplify-vue package implements a Vue EventBus for emitting and listening to events within it's components. The events emmitted by the components are listed within the documentation for each individual component. +The aws-amplify-vue package implements a Vue EventBus for emitting and listening to events within it's components. The events emmitted by the components are listed within the documentation for each individual component. To listen to these events within one of your components, import the EventBus: + ``` import { AmplifyEventBus } from 'aws-amplify-vue'; ``` Then, register an event listener (potentially within a lifecycle hook): + ``` AmplifyEventBus.$on('authState', info => { console.log(`Here is the auth event that was just emitted by an Amplify component: ${info}`) @@ -65,16 +67,15 @@ AmplifyEventBus.$on('authState', info => { ## AmplifyPlugin -The aws-amplify-vue package provides a Vue plugin to access the Amplify library. You installed the plugin when you set up your application: +The aws-amplify-vue package provides a Vue plugin to access the Amplify library. You installed the plugin when you set up your application: -```Vue.use(AmplifyPlugin, AmplifyModules);``` +`Vue.use(AmplifyPlugin, AmplifyModules);` -This makes the Amplify library available to the aws-amplify-vue components as well as to your application. Please note that you can restrict the modules that are made available to the plugin by passing only specific modules in the second argument of ```Vue.use``` call. +This makes the Amplify library available to the aws-amplify-vue components as well as to your application. Please note that you can restrict the modules that are made available to the plugin by passing only specific modules in the second argument of `Vue.use` call. ### Using the AmplifyPlugin -To call the Amplify library, simply use ``this.$Amplify.`` followed by whichever module you wish to use. - +To call the Amplify library, simply use `this.$Amplify.` followed by whichever module you wish to use. ## Authentication Components @@ -82,182 +83,183 @@ To call the Amplify library, simply use ``this.$Amplify.`` followed by whichever The Authenticator component provides basic basic login/logout functionality for your application, as well confirmation steps for new user registration and user login. It uses the following components as children: -* SignIn -* ConfirmSignIn -* SignUp -* ConfirmSignUp -* ForgotPassword +- SignIn +- ConfirmSignIn +- SignUp +- ConfirmSignUp +- ForgotPassword +Usage: `` -Usage: `````` - -Config: +Config: ``` ``` + | Attribute | Type | -|-----------------------------------------|--------| +| --------------------------------------- | ------ | | [confirmSignInConfig](#confirmsignin) | object | | [confirmSignUpConfig](#confirmsignup) | object | | [forgotPasswordConfig](#forgotpassword) | object | | [signInConfig](#signinconfig) | object | | [signUpConfig](#signupconfig) | object | -* The attributes above reference the config objects for the components that are nested inside Authenticator. See the individual components for details. - +\* The attributes above reference the config objects for the components that are nested inside Authenticator. See the individual components for details. Events: None ### SignIn -The SignIn component provides your users with the ability to sign in. +The SignIn component provides your users with the ability to sign in. -Usage: `````` +Usage: `` Config: + ``` ``` | Attribute | Type | Description | Default | Required | -|-----------|--------|-----------------------------------------|-----------|----------| +| --------- | ------ | --------------------------------------- | --------- | -------- | | header | string | the component header | 'Sign In' | no | | username | string | the default value of the username field | '' | no | -Events: +Events: -* ```AmplifyEventBus.$emit('authState', 'signedIn')```: Emitted when a user successfully signs in without answering an MFA challenge. -* ```AmplifyEventBus.$emit('authState', 'confirmSignIn')```: Emitted when a user successfully provides their credentials but is then asked to answer and MFA challenge. -* ```AmplifyEventBus.$emit('authState', 'forgotPassword')```: Emitted when a user clicks the 'Forgot Password' button. -* ```AmplifyEventBus.$emit('authState', 'signUp')```: Emitted when a user clicks 'Back to Sign Up'. +- `AmplifyEventBus.$emit('authState', 'signedIn')`: Emitted when a user successfully signs in without answering an MFA challenge. +- `AmplifyEventBus.$emit('authState', 'confirmSignIn')`: Emitted when a user successfully provides their credentials but is then asked to answer and MFA challenge. +- `AmplifyEventBus.$emit('authState', 'forgotPassword')`: Emitted when a user clicks the 'Forgot Password' button. +- `AmplifyEventBus.$emit('authState', 'signUp')`: Emitted when a user clicks 'Back to Sign Up'. ### ConfirmSignIn -The ConfirmSignIn component provides your users with the ability to answer an MFA challenge. +The ConfirmSignIn component provides your users with the ability to answer an MFA challenge. -Usage: `````` +Usage: `` Config: + ``` ``` | Attribute | Type | Description | Default | Required | -|-----------|--------|-----------------------------------------------------|-----------|----------| +| --------- | ------ | --------------------------------------------------- | --------- | -------- | | header | string | the component header | 'Sign In' | no | | user | object | the user who is stepping through the signin process | N/A | yes | +Events: -Events: - -* ```AmplifyEventBus.$emit('authState', 'signedIn')```: Emitted when a user successfully answers their MFA challenge. -* ```AmplifyEventBus.$emit('authState', 'signIn');```: Emitted when a user clicks 'Back to Sign In'. - +- `AmplifyEventBus.$emit('authState', 'signedIn')`: Emitted when a user successfully answers their MFA challenge. +- `AmplifyEventBus.$emit('authState', 'signIn');`: Emitted when a user clicks 'Back to Sign In'. ### SignUp -The SignUp component provides your users with the ability to sign up. +The SignUp component provides your users with the ability to sign up. -Usage: `````` +Usage: `` Config: + ``` ``` | Attribute | Type | Description | Default | Required | -|--------------|--------|-----------------------------|-----------------------------|----------| +| ------------ | ------ | --------------------------- | --------------------------- | -------- | | header | string | the component header | 'Sign Up' | no | | signUpFields | array | [see below](#signup-fields) | [see below](#signup-fields) | no | +Events: -Events: - -* ```AmplifyEventBus.$emit('authState', 'confirmSignUp')```: Emitted when a user successfully enters their information but has not yet completed a required verification step. -* ```AmplifyEventBus.$emit('authState', 'signIn')```: Emitted when a user successfully provides their information and does not need to complete a required verfication step, or when they click 'Back to Sign In'. - +- `AmplifyEventBus.$emit('authState', 'confirmSignUp')`: Emitted when a user successfully enters their information but has not yet completed a required verification step. +- `AmplifyEventBus.$emit('authState', 'signIn')`: Emitted when a user successfully provides their information and does not need to complete a required verfication step, or when they click 'Back to Sign In'. ### ConfirmSignUp -The ConfirmSignUp component provides your users with the ability to verify their identity. +The ConfirmSignUp component provides your users with the ability to verify their identity. -Usage: `````` +Usage: `` Config: + ``` ``` | Attribute | Type | Description | Default | Required | -|-----------|--------|-------------------------------------------|-------------------|----------| +| --------- | ------ | ----------------------------------------- | ----------------- | -------- | | header | string | the component header | 'Confirm Sign Up' | no | | username | string | the username of the user who is signingup | '' | no | +Events: -Events: - -* ```AmplifyEventBus.$emit('authState', 'signIn')```: Emitted when a user successfully completes their verification step or clicks 'Back to Sign In'. +- `AmplifyEventBus.$emit('authState', 'signIn')`: Emitted when a user successfully completes their verification step or clicks 'Back to Sign In'. ### ForgotPassword -The ForgotPassword component provides your users with the ability to reset their password. +The ForgotPassword component provides your users with the ability to reset their password. -Usage: `````` +Usage: `` Config: + ``` ``` -| Attribute | Type | Description | Default | Required | -|-----------|--------|-------------------------------------------|-------------------|----------| -| header | string | the component header | 'Forgot Password' | no | +| Attribute | Type | Description | Default | Required | +| --------- | ------ | -------------------- | ----------------- | -------- | +| header | string | the component header | 'Forgot Password' | no | -Events: +Events: -* ```AmplifyEventBus.$emit('authState', 'signIn')```: Emitted when a user successfully resets their password or clicks 'Back to Sign In'. +- `AmplifyEventBus.$emit('authState', 'signIn')`: Emitted when a user successfully resets their password or clicks 'Back to Sign In'. ### SignOut -The SignOut component provides your users with the ability to sign out. +The SignOut component provides your users with the ability to sign out. -Usage: `````` +Usage: `` Config: + ``` ``` | Attribute | Type | Description | Default | Required | -|---------------|--------|---------------------------------------------|------------|----------| +| ------------- | ------ | ------------------------------------------- | ---------- | -------- | | msg | string | message displayed above the sign out button | null | no | | signOutButton | string | text that appears in the sign out button | 'Sign Out' | no | -Events: +Events: -* ```AmplifyEventBus.$emit('authState', 'signedOut')```: Emitted when a user successfully signs out. +- `AmplifyEventBus.$emit('authState', 'signedOut')`: Emitted when a user successfully signs out. ### SetMFA -The SetMFA component provides your users with the ability to set their preferred Multifactor Authentication (MFA) method. It has the ability to show three options - SMS Text Message, TOTP, or None (depending on the options that you pass into it). +The SetMFA component provides your users with the ability to set their preferred Multifactor Authentication (MFA) method. It has the ability to show three options - SMS Text Message, TOTP, or None (depending on the options that you pass into it). -Usage: `````` +Usage: `` Config: + ``` ``` | Attribute | Type | Description | Default | Possible Values | Required | -|-------------------|----------|---------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|-----------------------|----------| +| ----------------- | -------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | --------------------- | -------- | | mfaDescription | string | description of MFA for your users | AWS Multi-Factor Authentication (MFA) adds an extra layer of protection on top of your user name and password. | N/A | no | | mfaTypes | array | an array of MFA types which will result in a radio button selection | [] | 'SMS', 'TOTP', 'None' | no | | tokenInstructions | string | instructions for decoding the QR code used with TOTP | 'Scan the QR Code with your phone camera or authentication app to get the MFA code.' | N/A | no | | smsDescription | string | label for SMS radio button | 'SMS text messaging (receive a code on your mobile device)' | N/A | no | | totpDescription | string | label for TOTP radio button | 'One-time password (use a QR code and MFA app to save a token on your mobile device)' | N/A | no | | noMfaDescription | string | label for 'None' radio button | 'Do not enable MFA' | N/A | no | -| cancelHandler | function | function called when user clicks on 'Cancel' button | None | N/A | no | +| cancelHandler | function | function called when user clicks on 'Cancel' button | None | N/A | no | Events: None @@ -265,26 +267,24 @@ Events: None The `aws-amplify-vue` SignUp component allows you to programatically define the user input fields that are displayed to the user. Information entered into these fields will populate the user's record in your User Pool. -Usage: +Usage: ``` -``` +``` | Attribute | Type | Description | Possible Values | -|--------------|--------|---------------------------------------------------------------|--------------------------------| +| ------------ | ------ | ------------------------------------------------------------- | ------------------------------ | | label | string | label for the input field | N/A | | key | string | key name for the attribute as defined in the User Pool | N/A | | required | bolean | whether or not the field is required | N/A | | displayOrder | number | number indicating the order in which fields will be displayed | N/A | | type | string | the type attribute for the html input element | 'string', 'number', 'password' | - -By default the SignUp Component will display Username, Password, Email and Phone Number fields (all required, and in that order). You can override the labels, displayOrder or 'required' booleans for these fields by passing objects with 'username', 'password', 'email' or 'phone_number' keys in the signUpConfig.signUpFields array. +By default the SignUp Component will display Username, Password, Email and Phone Number fields (all required, and in that order). You can override the labels, displayOrder or 'required' booleans for these fields by passing objects with 'username', 'password', 'email' or 'phone_number' keys in the signUpConfig.signUpFields array. Fields passed into the signUpFields array without a displayOrder property will be placed after those fields with defined displayOrders and in alphabetical order by key. - ## API Components ### Connect @@ -454,43 +454,41 @@ export default { ``` - ## Storage Components ### PhotoPicker The PhotoPicker component provides your users to select and preview a file for upload to S3. -Usage: `````` +Usage: `` Config: + ``` ``` | Attribute | Type | Description | Default | Required | -|-------------|--------|------------------------------------------------------------------------|--------------------|----------| +| ----------- | ------ | ---------------------------------------------------------------------- | ------------------ | -------- | | header | string | the component header | 'File Upload' | no | | title | string | text displayed in the upload button | 'Upload' | no | -| accept | string | a string representing the 'accept' attribute in the html input element | '*/*' | no | +| accept | string | a string representing the 'accept' attribute in the html input element | '_/_' | no | | path | string | S3 path for the file upload | N/A | yes | | defaultName | string | the name of the file when uploaded to S3 | original file name | no | Events: -* ```AmplifyEventBus.$emit('fileUpload', img)```: Emitted when a file is uploaded (includes the image path) - +- `AmplifyEventBus.$emit('fileUpload', img)`: Emitted when a file is uploaded (includes the image path) ### S3Album The S3Album component displays the image files from the provided S3 path. -Usage: `````` +Usage: `` Props: -The S3Album component does not have a config object like most other amplify-vue components. Instead it receives the S3 directory path as a string. The path is required. - +The S3Album component does not have a config object like most other amplify-vue components. Instead it receives the S3 directory path as a string. The path is required. Events: None @@ -498,11 +496,11 @@ Events: None The S3Image component displays a single image from the provided path. -Usage: `````` +Usage: `` Props: -The S3Image component does not have a config object like most other amplify-vue components. Instead it receives the S3 image path as a string. The path is required. +The S3Image component does not have a config object like most other amplify-vue components. Instead it receives the S3 image path as a string. The path is required. Events: None @@ -512,21 +510,22 @@ Events: None The Chatbot component allows your users to interact with an Amazon Lex chatbot. -Usage: `````` +Usage: `` Config: + ``` ``` | Attribute | Type | Description | Default | Required | -|---------------|---------|-----------------------------------------------------------------------------------------------|-----------|----------| +| ------------- | ------- | --------------------------------------------------------------------------------------------- | --------- | -------- | | bot | string | the name of the chatbot as defined in your Amplify configuration under "aws_bots_config.name" | N/A | yes | | clearComplete | boolean | specifies whether the chat messages clear out at the end of the chat session | true | no | | botTitle | string | the name of the chatbot component in your frontend app | 'Chatbot' | no | - If not in your aws.exports file, the bot can also be defined in the AWS configure method: + ``` Interactions: { bots: { @@ -541,4 +540,4 @@ If not in your aws.exports file, the bot can also be defined in the AWS configur Events: -* ```AmplifyEventBus.$emit('chatComplete', this.options.botTitle)```: Emitted when a chat session has been completed (only if the clearComplete options is 'true') +- `AmplifyEventBus.$emit('chatComplete', this.options.botTitle)`: Emitted when a chat session has been completed (only if the clearComplete options is 'true') diff --git a/packages/aws-amplify-vue/__mocks__/Amplify.mocks.js b/packages/aws-amplify-vue/__mocks__/Amplify.mocks.js index b8687d6dacf..aa47f9534a2 100644 --- a/packages/aws-amplify-vue/__mocks__/Amplify.mocks.js +++ b/packages/aws-amplify-vue/__mocks__/Amplify.mocks.js @@ -1,52 +1,64 @@ module.exports = { - Logger: function Logger(name) { - this.name = name; - this.info = jest.fn(); - this.error = jest.fn(); - }, - Auth: { - currentAuthenticatedUser: jest.fn(() => Promise.resolve({})), - verifyCurrentUserAttribute: jest.fn(() => Promise.resolve({ username: 'myTestUsername' })), - completeNewPassword: jest.fn(() => Promise.resolve({})), - confirmSignIn: jest.fn(() => Promise.resolve({})), - confirmSignUp: jest.fn(() => Promise.resolve({})), - forgotPassword: jest.fn(() => Promise.resolve({})), - forgotPasswordSubmit: jest.fn(() => Promise.resolve({})), - resendSignUp: jest.fn(() => Promise.resolve({})), - setPreferredMFA: jest.fn(() => Promise.resolve({})), - setupTOTP: jest.fn(() => Promise.resolve('gibberish')), - signIn: jest.fn(() => Promise.resolve({ - challengeName: 'CUSTOM_CHALLENGE', - challengeParam: { trigger: 'true' }, - })), - signOut: jest.fn(() => Promise.resolve({})), - signUp: jest.fn(() => Promise.resolve({})), - verifiedContact: jest.fn(() => Promise.resolve({})), - verifyTotpToken: jest.fn(() => Promise.resolve({})), - }, - AuthClass: {}, - Interactions: { - onComplete: jest.fn(() => Promise.resolve({})), - send: jest.fn(() => Promise.resolve({})), - }, - Storage: { - get: jest.fn(() => Promise.resolve({})), - put: jest.fn(() => Promise.resolve({ key: 'testKey' })), - list: jest.fn(() => Promise.resolve({})), - }, - I18n: { - get: jest.fn(key => { return `i18n ${key}` }), - }, - XR: { - loadScene: jest.fn(() => Promise.resolve({})), - start: jest.fn(), - isMuted: jest.fn(() => { return false }), - isVRCapable: jest.fn(() => { return false }), - onSceneEvent: jest.fn(), - setMuted: jest.fn(), - enableAudio: jest.fn(), - enterVR: jest.fn(), - exitVR: jest.fn(), - isVRPresentationActive: jest.fn(() => { return false }) - } + Logger: function Logger(name) { + this.name = name; + this.info = jest.fn(); + this.error = jest.fn(); + }, + Auth: { + currentAuthenticatedUser: jest.fn(() => Promise.resolve({})), + verifyCurrentUserAttribute: jest.fn(() => + Promise.resolve({ username: 'myTestUsername' }) + ), + completeNewPassword: jest.fn(() => Promise.resolve({})), + confirmSignIn: jest.fn(() => Promise.resolve({})), + confirmSignUp: jest.fn(() => Promise.resolve({})), + forgotPassword: jest.fn(() => Promise.resolve({})), + forgotPasswordSubmit: jest.fn(() => Promise.resolve({})), + resendSignUp: jest.fn(() => Promise.resolve({})), + setPreferredMFA: jest.fn(() => Promise.resolve({})), + setupTOTP: jest.fn(() => Promise.resolve('gibberish')), + signIn: jest.fn(() => + Promise.resolve({ + challengeName: 'CUSTOM_CHALLENGE', + challengeParam: { trigger: 'true' }, + }) + ), + signOut: jest.fn(() => Promise.resolve({})), + signUp: jest.fn(() => Promise.resolve({})), + verifiedContact: jest.fn(() => Promise.resolve({})), + verifyTotpToken: jest.fn(() => Promise.resolve({})), + }, + AuthClass: {}, + Interactions: { + onComplete: jest.fn(() => Promise.resolve({})), + send: jest.fn(() => Promise.resolve({})), + }, + Storage: { + get: jest.fn(() => Promise.resolve({})), + put: jest.fn(() => Promise.resolve({ key: 'testKey' })), + list: jest.fn(() => Promise.resolve({})), + }, + I18n: { + get: jest.fn(key => { + return `i18n ${key}`; + }), + }, + XR: { + loadScene: jest.fn(() => Promise.resolve({})), + start: jest.fn(), + isMuted: jest.fn(() => { + return false; + }), + isVRCapable: jest.fn(() => { + return false; + }), + onSceneEvent: jest.fn(), + setMuted: jest.fn(), + enableAudio: jest.fn(), + enterVR: jest.fn(), + exitVR: jest.fn(), + isVRPresentationActive: jest.fn(() => { + return false; + }), + }, }; diff --git a/packages/aws-amplify-vue/__tests__/Amplify.test.js b/packages/aws-amplify-vue/__tests__/Amplify.test.js index 525cbd362ca..38d140a00f6 100644 --- a/packages/aws-amplify-vue/__tests__/Amplify.test.js +++ b/packages/aws-amplify-vue/__tests__/Amplify.test.js @@ -7,26 +7,23 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('Amplify (root vue)', () => { - let Component; - let vm; + let Component; + let vm; + beforeEach(() => { + Component = Vue.extend(App); + vm = new Component({}).$mount(); + }); - beforeEach(() => { - Component = Vue.extend(App); - vm = new Component({ - }).$mount(); - }); + it('...should be named "amplify"', () => { + expect(vm.$options.name).toEqual('amplify'); + }); + it('...should import the AmplifyEventBus', () => { + expect(vm.$options.AmplifyEventBus).toEqual(AmplifyEventBus); + }); - it('...should be named "amplify"', () => { - expect(vm.$options.name).toEqual('amplify'); - }); - - it('...should import the AmplifyEventBus', () => { - expect(vm.$options.AmplifyEventBus).toEqual(AmplifyEventBus); - }); - - it('...should use the amplify plugin with passed modules', () => { - expect(vm.$Amplify).toBeTruthy(); - }); + it('...should use the amplify plugin with passed modules', () => { + expect(vm.$Amplify).toBeTruthy(); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/AmplifyPlugin.test.js b/packages/aws-amplify-vue/__tests__/AmplifyPlugin.test.js index cc93c3a53db..bac10ae1640 100644 --- a/packages/aws-amplify-vue/__tests__/AmplifyPlugin.test.js +++ b/packages/aws-amplify-vue/__tests__/AmplifyPlugin.test.js @@ -5,17 +5,15 @@ import AmplifyPlugin from '../src/plugins/AmplifyPlugin'; Vue.use(AmplifyPlugin, {}); describe('AmplifyPlugin edge case...', () => { - let Component; - let vm; + let Component; + let vm; + beforeEach(() => { + Component = Vue.extend(App); + vm = new Component({}).$mount(); + }); - beforeEach(() => { - Component = Vue.extend(App); - vm = new Component({ - }).$mount(); - }); - - it('...the plugin install should fail if modules are not passed', () => { - expect(vm.$Amplify).toBeFalsy(); - }); + it('...the plugin install should fail if modules are not passed', () => { + expect(vm.$Amplify).toBeFalsy(); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/Authenticator.test.js b/packages/aws-amplify-vue/__tests__/Authenticator.test.js index 2a6a7e16f7b..23162fed6d9 100644 --- a/packages/aws-amplify-vue/__tests__/Authenticator.test.js +++ b/packages/aws-amplify-vue/__tests__/Authenticator.test.js @@ -12,119 +12,119 @@ Vue.use(AmplifyPlugin, AmplifyMocks); jest.mock('../src/services/getUser'); describe('Authenticator', () => { - it('has a mounted hook', () => { - expect(typeof Authenticator.mounted).toBe('function'); - }); - - it('sets the correct default data', () => { - expect(typeof Authenticator.data).toBe('function'); - const defaultData = Authenticator.data(); - expect(defaultData.user.username).toBe(null); - expect(defaultData.logger).toEqual({}); - expect(defaultData.displayMap).toEqual({}); - expect(defaultData.error).toEqual(''); - }); - - describe('...when it is mounted...', () => { - let wrapper; - - beforeEach(() => { - wrapper = shallowMount(Authenticator); - dependency.mockImplementation(() => Promise.resolve({})); - }); - - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); - - it('...it should be named Authenticator', () => { - expect(wrapper.vm.$options.name).toEqual('Authenticator'); - }); - - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); - - it('...it should have an updateDisplayMap method', () => { - expect(wrapper.vm.updateDisplayMap).toBeTruthy(); - }); - - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); - - it('...it should call GetUser', () => { - expect(dependency).toBeCalledWith(AmplifyMocks); - }); - }); - - describe('...when it is mounted and displaying components...', () => { - let wrapper; - let mockDisplayMap = {}; - beforeEach(() => { - wrapper = shallowMount(Authenticator, { - // methods: { - // updateDisplayMap: mockUpdateDisplayMap, - // } - }); - wrapper.vm.updateDisplayMap = jest.fn(() => mockDisplayMap); - dependency.mockImplementation(() => Promise.reject(new Error())); - mockDisplayMap = { - showSignIn: false, - showSignUp: false, - showConfirmSignUp: false, - showConfirmSignIn: false, - showForgotPassword: false, - }; - }); - - afterEach(() => { - wrapper.vm.displayMap = {}; - }); - - it('...it should call updateDisplayMap', () => { - expect(wrapper.vm.updateDisplayMap).toBeCalled(); - }); - - it('...it should display the signIn component based on displayMap', () => { - mockDisplayMap.showSignIn = true; - wrapper.vm.displayMap = mockDisplayMap; - const el = wrapper.find(components.SignIn).element; - expect(el).toBeTruthy(); - }); - - it('...it should display the signUp component based on displayMap', () => { - mockDisplayMap.showSignUp = true; - wrapper.vm.displayMap = mockDisplayMap; - const el = wrapper.find(components.SignUp).element; - expect(el).toBeTruthy(); - }); - - it('...it should display the confirmSignUp component based on displayMap', () => { - mockDisplayMap.showConfirmSignUp = true; - wrapper.vm.displayMap = mockDisplayMap; - const el = wrapper.find(components.ConfirmSignUp).element; - expect(el).toBeTruthy(); - }); - - it('...it should display the ConfirmSignIn component based on displayMap', () => { - mockDisplayMap.showConfirmSignIn = true; - wrapper.vm.displayMap = mockDisplayMap; - const el = wrapper.find(components.ConfirmSignIn).element; - expect(el).toBeTruthy(); - }); - - it('...it should display the ForgotPassword component based on displayMap', () => { - mockDisplayMap.showForgotPassword = true; - wrapper.vm.displayMap = mockDisplayMap; - const el = wrapper.find(components.ForgotPassword).element; - expect(el).toBeTruthy(); - }); - - it('...should set user and options data on localUser event emission', () => { - const testUser = { username: 'IAMEMITTED' }; - AmplifyEventBus.$emit('localUser', testUser); - expect(wrapper.vm.user.username).toEqual(testUser.username); - }); - }); + it('has a mounted hook', () => { + expect(typeof Authenticator.mounted).toBe('function'); + }); + + it('sets the correct default data', () => { + expect(typeof Authenticator.data).toBe('function'); + const defaultData = Authenticator.data(); + expect(defaultData.user.username).toBe(null); + expect(defaultData.logger).toEqual({}); + expect(defaultData.displayMap).toEqual({}); + expect(defaultData.error).toEqual(''); + }); + + describe('...when it is mounted...', () => { + let wrapper; + + beforeEach(() => { + wrapper = shallowMount(Authenticator); + dependency.mockImplementation(() => Promise.resolve({})); + }); + + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); + + it('...it should be named Authenticator', () => { + expect(wrapper.vm.$options.name).toEqual('Authenticator'); + }); + + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); + + it('...it should have an updateDisplayMap method', () => { + expect(wrapper.vm.updateDisplayMap).toBeTruthy(); + }); + + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); + + it('...it should call GetUser', () => { + expect(dependency).toBeCalledWith(AmplifyMocks); + }); + }); + + describe('...when it is mounted and displaying components...', () => { + let wrapper; + let mockDisplayMap = {}; + beforeEach(() => { + wrapper = shallowMount(Authenticator, { + // methods: { + // updateDisplayMap: mockUpdateDisplayMap, + // } + }); + wrapper.vm.updateDisplayMap = jest.fn(() => mockDisplayMap); + dependency.mockImplementation(() => Promise.reject(new Error())); + mockDisplayMap = { + showSignIn: false, + showSignUp: false, + showConfirmSignUp: false, + showConfirmSignIn: false, + showForgotPassword: false, + }; + }); + + afterEach(() => { + wrapper.vm.displayMap = {}; + }); + + it('...it should call updateDisplayMap', () => { + expect(wrapper.vm.updateDisplayMap).toBeCalled(); + }); + + it('...it should display the signIn component based on displayMap', () => { + mockDisplayMap.showSignIn = true; + wrapper.vm.displayMap = mockDisplayMap; + const el = wrapper.find(components.SignIn).element; + expect(el).toBeTruthy(); + }); + + it('...it should display the signUp component based on displayMap', () => { + mockDisplayMap.showSignUp = true; + wrapper.vm.displayMap = mockDisplayMap; + const el = wrapper.find(components.SignUp).element; + expect(el).toBeTruthy(); + }); + + it('...it should display the confirmSignUp component based on displayMap', () => { + mockDisplayMap.showConfirmSignUp = true; + wrapper.vm.displayMap = mockDisplayMap; + const el = wrapper.find(components.ConfirmSignUp).element; + expect(el).toBeTruthy(); + }); + + it('...it should display the ConfirmSignIn component based on displayMap', () => { + mockDisplayMap.showConfirmSignIn = true; + wrapper.vm.displayMap = mockDisplayMap; + const el = wrapper.find(components.ConfirmSignIn).element; + expect(el).toBeTruthy(); + }); + + it('...it should display the ForgotPassword component based on displayMap', () => { + mockDisplayMap.showForgotPassword = true; + wrapper.vm.displayMap = mockDisplayMap; + const el = wrapper.find(components.ForgotPassword).element; + expect(el).toBeTruthy(); + }); + + it('...should set user and options data on localUser event emission', () => { + const testUser = { username: 'IAMEMITTED' }; + AmplifyEventBus.$emit('localUser', testUser); + expect(wrapper.vm.user.username).toEqual(testUser.username); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/Chatbot.test.js b/packages/aws-amplify-vue/__tests__/Chatbot.test.js index 152b49632db..a638e1aa88b 100644 --- a/packages/aws-amplify-vue/__tests__/Chatbot.test.js +++ b/packages/aws-amplify-vue/__tests__/Chatbot.test.js @@ -11,179 +11,180 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('Chatbot', () => { - it('has a mounted hook', () => { - expect(typeof Chatbot.mounted).toBe('function'); - }); - - it('sets the correct default data', () => { - expect(typeof Chatbot.data).toBe('function'); - const defaultData = Chatbot.data(); - expect(defaultData.inputText).toBe(''); - expect(defaultData.messages.length).toEqual(0); - expect(defaultData.logger).toEqual({}); - expect(defaultData.error).toEqual(''); - }); - - let wrapper; - let testState; - const mockPerformOnComplete = jest.fn(); - const mockKeymonitor = jest.fn(); - const mockOnSubmit = jest.fn(); - const mockSetError = jest.fn(); - - describe('...when it is mounted without props...', () => { - beforeEach(() => { - wrapper = shallowMount(Chatbot); - testState = null; - }); - - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); - - it('...it should be named Chatbot', () => { - expect(wrapper.vm.$options.name).toEqual('Chatbot'); - }); - - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); - - it('...it should have a performOnComplete method', () => { - expect(wrapper.vm.performOnComplete).toBeTruthy(); - }); - - it('...it should have a keymonitor method', () => { - expect(wrapper.vm.keymonitor).toBeTruthy(); - }); - - it('...it should have an onSubmit method', () => { - expect(wrapper.vm.onSubmit).toBeTruthy(); - }); - - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); - - it('...have default options', () => { - expect(wrapper.vm.options.clearComplete).toEqual(true); - expect(wrapper.vm.options.botTitle).toEqual('Chatbot'); - }); - - it('...should return immediately when onSubmit is called without inputText', () => { - wrapper.vm.onSubmit({}); - expect(wrapper.vm.$Amplify.Interactions.send).not.toHaveBeenCalled(); - }); - - it('...should call $Amplify.Interactions.send when onSubmit is called with inputText', () => { - wrapper.vm.inputText = 'i exist'; - wrapper.vm.onSubmit({}); - expect(wrapper.vm.$Amplify.Interactions.send).toHaveBeenCalled(); - }); - - it('...should emit chatComplete when performOnComplete method called', () => { - testState = 0; - AmplifyEventBus.$on('chatComplete', (val) => { - if (val === wrapper.vm.options.botTitle) { - testState = 3; - } - }); - wrapper.vm.performOnComplete(); - expect(testState).toEqual(3); - }); - - it('...should emit clear messages when performOnComplete method and clearComplete is true', () => { // eslint-disable-line - wrapper.vm.messages = ['messages']; - wrapper.vm.performOnComplete(); - expect(wrapper.vm.messages).toEqual([]); - }); - }); - - describe('...when only onSubmit is mocked', () => { - let botTitle; - let clearComplete; - let bot; - beforeEach(() => { - botTitle = 'TestBot'; - clearComplete = 'Get Outta Here'; - bot = 'TestBotName'; - wrapper = shallowMount(Chatbot, { - methods: { - onSubmit: mockOnSubmit, - }, - propsData: { - chatbotConfig: { - botTitle, - clearComplete, - bot, - }, - }, - }); - }); - - afterEach(() => { - mockOnSubmit.mockReset(); - }); - - it('...should not call onSubmit when keymonitor is called with key other than Enter', () => { - wrapper.vm.keymonitor({ key: 'r' }); - expect(mockOnSubmit).not.toHaveBeenCalled(); - }); - - it('...should call onSubmit when keymonitor is called with Enter', () => { - wrapper.vm.keymonitor({ key: 'enter' }); - expect(mockOnSubmit).toHaveBeenCalled(); - }); - }); - - describe('...when it is mounted with props...', () => { - let botTitle; - let clearComplete; - let bot; - beforeEach(() => { - botTitle = 'TestBot'; - clearComplete = 'Get Outta Here'; - bot = 'TestBotName'; - wrapper = shallowMount(Chatbot, { - methods: { - performOnComplete: mockPerformOnComplete, - keymonitor: mockKeymonitor, - onSubmit: mockOnSubmit, - setError: mockSetError, - }, - propsData: { - chatbotConfig: { - botTitle, - clearComplete, - bot, - }, - }, - }); - }); - - afterEach(() => { - mockPerformOnComplete.mockReset(); - mockKeymonitor.mockReset(); - mockSetError.mockReset(); - mockOnSubmit.mockReset(); - }); - - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); - - it('...should call onSubmit with inputText when submit button is clicked', () => { - const el = wrapper.find('#interactions-submit-button'); - wrapper.vm.inputText = 'talk to me, robot'; - el.trigger('click'); - expect(mockOnSubmit).toHaveBeenCalledWith('talk to me, robot'); - }); - - it('...should call keymonitor when key events occur in input', () => { - const input = wrapper.find('.amplify-interactions-actions > input'); - input.trigger('keyup', { keyCode: 40 }); - expect(mockKeymonitor).toHaveBeenCalled(); - }); - }); + it('has a mounted hook', () => { + expect(typeof Chatbot.mounted).toBe('function'); + }); + + it('sets the correct default data', () => { + expect(typeof Chatbot.data).toBe('function'); + const defaultData = Chatbot.data(); + expect(defaultData.inputText).toBe(''); + expect(defaultData.messages.length).toEqual(0); + expect(defaultData.logger).toEqual({}); + expect(defaultData.error).toEqual(''); + }); + + let wrapper; + let testState; + const mockPerformOnComplete = jest.fn(); + const mockKeymonitor = jest.fn(); + const mockOnSubmit = jest.fn(); + const mockSetError = jest.fn(); + + describe('...when it is mounted without props...', () => { + beforeEach(() => { + wrapper = shallowMount(Chatbot); + testState = null; + }); + + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); + + it('...it should be named Chatbot', () => { + expect(wrapper.vm.$options.name).toEqual('Chatbot'); + }); + + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); + + it('...it should have a performOnComplete method', () => { + expect(wrapper.vm.performOnComplete).toBeTruthy(); + }); + + it('...it should have a keymonitor method', () => { + expect(wrapper.vm.keymonitor).toBeTruthy(); + }); + + it('...it should have an onSubmit method', () => { + expect(wrapper.vm.onSubmit).toBeTruthy(); + }); + + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); + + it('...have default options', () => { + expect(wrapper.vm.options.clearComplete).toEqual(true); + expect(wrapper.vm.options.botTitle).toEqual('Chatbot'); + }); + + it('...should return immediately when onSubmit is called without inputText', () => { + wrapper.vm.onSubmit({}); + expect(wrapper.vm.$Amplify.Interactions.send).not.toHaveBeenCalled(); + }); + + it('...should call $Amplify.Interactions.send when onSubmit is called with inputText', () => { + wrapper.vm.inputText = 'i exist'; + wrapper.vm.onSubmit({}); + expect(wrapper.vm.$Amplify.Interactions.send).toHaveBeenCalled(); + }); + + it('...should emit chatComplete when performOnComplete method called', () => { + testState = 0; + AmplifyEventBus.$on('chatComplete', val => { + if (val === wrapper.vm.options.botTitle) { + testState = 3; + } + }); + wrapper.vm.performOnComplete(); + expect(testState).toEqual(3); + }); + + it('...should emit clear messages when performOnComplete method and clearComplete is true', () => { + // eslint-disable-line + wrapper.vm.messages = ['messages']; + wrapper.vm.performOnComplete(); + expect(wrapper.vm.messages).toEqual([]); + }); + }); + + describe('...when only onSubmit is mocked', () => { + let botTitle; + let clearComplete; + let bot; + beforeEach(() => { + botTitle = 'TestBot'; + clearComplete = 'Get Outta Here'; + bot = 'TestBotName'; + wrapper = shallowMount(Chatbot, { + methods: { + onSubmit: mockOnSubmit, + }, + propsData: { + chatbotConfig: { + botTitle, + clearComplete, + bot, + }, + }, + }); + }); + + afterEach(() => { + mockOnSubmit.mockReset(); + }); + + it('...should not call onSubmit when keymonitor is called with key other than Enter', () => { + wrapper.vm.keymonitor({ key: 'r' }); + expect(mockOnSubmit).not.toHaveBeenCalled(); + }); + + it('...should call onSubmit when keymonitor is called with Enter', () => { + wrapper.vm.keymonitor({ key: 'enter' }); + expect(mockOnSubmit).toHaveBeenCalled(); + }); + }); + + describe('...when it is mounted with props...', () => { + let botTitle; + let clearComplete; + let bot; + beforeEach(() => { + botTitle = 'TestBot'; + clearComplete = 'Get Outta Here'; + bot = 'TestBotName'; + wrapper = shallowMount(Chatbot, { + methods: { + performOnComplete: mockPerformOnComplete, + keymonitor: mockKeymonitor, + onSubmit: mockOnSubmit, + setError: mockSetError, + }, + propsData: { + chatbotConfig: { + botTitle, + clearComplete, + bot, + }, + }, + }); + }); + + afterEach(() => { + mockPerformOnComplete.mockReset(); + mockKeymonitor.mockReset(); + mockSetError.mockReset(); + mockOnSubmit.mockReset(); + }); + + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); + + it('...should call onSubmit with inputText when submit button is clicked', () => { + const el = wrapper.find('#interactions-submit-button'); + wrapper.vm.inputText = 'talk to me, robot'; + el.trigger('click'); + expect(mockOnSubmit).toHaveBeenCalledWith('talk to me, robot'); + }); + + it('...should call keymonitor when key events occur in input', () => { + const input = wrapper.find('.amplify-interactions-actions > input'); + input.trigger('keyup', { keyCode: 40 }); + expect(mockKeymonitor).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/ConfirmSignIn.test.js b/packages/aws-amplify-vue/__tests__/ConfirmSignIn.test.js index 7e8f036a396..0fbceeaef4d 100644 --- a/packages/aws-amplify-vue/__tests__/ConfirmSignIn.test.js +++ b/packages/aws-amplify-vue/__tests__/ConfirmSignIn.test.js @@ -11,130 +11,132 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('ConfirmSignIn', () => { - it('has a mounted hook', () => { - expect(typeof ConfirmSignIn.mounted).toBe('function'); - }); - - it('sets the correct default data', () => { - expect(typeof ConfirmSignIn.data).toBe('function'); - const defaultData = ConfirmSignIn.data(); - expect(defaultData.code).toBe(''); - expect(defaultData.logger).toEqual({}); - expect(defaultData.error).toEqual(''); - }); - - let wrapper; - let header; - const mockSend = jest.fn(); - const mockSubmit = jest.fn(); - const mockSignIn = jest.fn(); - const mockSetError = jest.fn(); - let testState; - - describe('...when it is mounted without props...', () => { - beforeEach(() => { - wrapper = shallowMount(ConfirmSignIn); - }); - - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); - - it('...it should be named ConfirmSignIn', () => { - expect(wrapper.vm.$options.name).toEqual('ConfirmSignIn'); - }); - - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); - - it('...should have a submit method', () => { - expect(wrapper.vm.submit).toBeTruthy(); - }); - - it('...should have a signIn method', () => { - expect(wrapper.vm.signIn).toBeTruthy(); - }); - - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); - - it('...have default options', () => { - expect(wrapper.vm.options.header).toEqual('i18n Confirm Sign In'); - expect(Object.keys(wrapper.vm.options.user).length).toEqual(0); - }); - - it('...should set the error property when a valid user is not received', () => { - expect(wrapper.vm.error).toEqual('i18n Valid user not received.'); - }); - - it('...should call Auth.confirmSignIn when submit function is called', () => { - wrapper.vm.submit(); - expect(AmplifyMocks.Auth.confirmSignIn).toHaveBeenCalled(); - }); - - it('...should call emit the authState event when signIn function is called', () => { - AmplifyEventBus.$on('authState', () => { - testState = 'eventsAreEmitting'; - }); - expect(testState).toBeUndefined(); - wrapper.vm.signIn(); - expect(testState).toEqual('eventsAreEmitting'); - }); - }); - - describe('...when it is mounted with props...', () => { - beforeEach(() => { - header = 'TestHeader'; - wrapper = shallowMount(ConfirmSignIn, { - methods: { - submit: mockSubmit, - signIn: mockSignIn, - setError: mockSetError, - }, - propsData: { - confirmSignInConfig: { - user: { username: 'TestPerson' }, - header, - }, - }, - }); - }); - - afterEach(() => { - mockSend.mockReset(); - mockSubmit.mockReset(); - mockSignIn.mockReset(); - mockSetError.mockReset(); - }); - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); - - it('...should render the header from props', () => { - const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; - expect(el.textContent).toEqual(header); - }); - - it('...should not call submit when submit button is clicked but code is not present', () => { - const el = wrapper.find('button'); - el.trigger('click'); - expect(mockSubmit).not.toHaveBeenCalled(); - }); - - it('...should call submit when submit button is clicked and code is present', () => { - const el = wrapper.find('button'); - wrapper.vm.code = 123456; - el.trigger('click'); - expect(mockSubmit).toHaveBeenCalled(); - }); - - it('...should call signIn when signIn button is clicked', () => { - const el = wrapper.find(`.${AmplifyUI.sectionFooterSecondaryContent} > .${AmplifyUI.a}`); - el.trigger('click'); - expect(mockSignIn).toHaveBeenCalled(); - }); - }); + it('has a mounted hook', () => { + expect(typeof ConfirmSignIn.mounted).toBe('function'); + }); + + it('sets the correct default data', () => { + expect(typeof ConfirmSignIn.data).toBe('function'); + const defaultData = ConfirmSignIn.data(); + expect(defaultData.code).toBe(''); + expect(defaultData.logger).toEqual({}); + expect(defaultData.error).toEqual(''); + }); + + let wrapper; + let header; + const mockSend = jest.fn(); + const mockSubmit = jest.fn(); + const mockSignIn = jest.fn(); + const mockSetError = jest.fn(); + let testState; + + describe('...when it is mounted without props...', () => { + beforeEach(() => { + wrapper = shallowMount(ConfirmSignIn); + }); + + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); + + it('...it should be named ConfirmSignIn', () => { + expect(wrapper.vm.$options.name).toEqual('ConfirmSignIn'); + }); + + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); + + it('...should have a submit method', () => { + expect(wrapper.vm.submit).toBeTruthy(); + }); + + it('...should have a signIn method', () => { + expect(wrapper.vm.signIn).toBeTruthy(); + }); + + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); + + it('...have default options', () => { + expect(wrapper.vm.options.header).toEqual('i18n Confirm Sign In'); + expect(Object.keys(wrapper.vm.options.user).length).toEqual(0); + }); + + it('...should set the error property when a valid user is not received', () => { + expect(wrapper.vm.error).toEqual('i18n Valid user not received.'); + }); + + it('...should call Auth.confirmSignIn when submit function is called', () => { + wrapper.vm.submit(); + expect(AmplifyMocks.Auth.confirmSignIn).toHaveBeenCalled(); + }); + + it('...should call emit the authState event when signIn function is called', () => { + AmplifyEventBus.$on('authState', () => { + testState = 'eventsAreEmitting'; + }); + expect(testState).toBeUndefined(); + wrapper.vm.signIn(); + expect(testState).toEqual('eventsAreEmitting'); + }); + }); + + describe('...when it is mounted with props...', () => { + beforeEach(() => { + header = 'TestHeader'; + wrapper = shallowMount(ConfirmSignIn, { + methods: { + submit: mockSubmit, + signIn: mockSignIn, + setError: mockSetError, + }, + propsData: { + confirmSignInConfig: { + user: { username: 'TestPerson' }, + header, + }, + }, + }); + }); + + afterEach(() => { + mockSend.mockReset(); + mockSubmit.mockReset(); + mockSignIn.mockReset(); + mockSetError.mockReset(); + }); + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); + + it('...should render the header from props', () => { + const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; + expect(el.textContent).toEqual(header); + }); + + it('...should not call submit when submit button is clicked but code is not present', () => { + const el = wrapper.find('button'); + el.trigger('click'); + expect(mockSubmit).not.toHaveBeenCalled(); + }); + + it('...should call submit when submit button is clicked and code is present', () => { + const el = wrapper.find('button'); + wrapper.vm.code = 123456; + el.trigger('click'); + expect(mockSubmit).toHaveBeenCalled(); + }); + + it('...should call signIn when signIn button is clicked', () => { + const el = wrapper.find( + `.${AmplifyUI.sectionFooterSecondaryContent} > .${AmplifyUI.a}` + ); + el.trigger('click'); + expect(mockSignIn).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/ConfirmSignUp.test.js b/packages/aws-amplify-vue/__tests__/ConfirmSignUp.test.js index 26935e96b32..669c1e259f4 100644 --- a/packages/aws-amplify-vue/__tests__/ConfirmSignUp.test.js +++ b/packages/aws-amplify-vue/__tests__/ConfirmSignUp.test.js @@ -11,145 +11,146 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('ConfirmSignUp', () => { - it('has a mounted hook', () => { - expect(typeof ConfirmSignUp.mounted).toBe('function'); - }); - - it('sets the correct default data', () => { - expect(typeof ConfirmSignUp.data).toBe('function'); - const defaultData = ConfirmSignUp.data(); - expect(defaultData.code).toBe(''); - expect(defaultData.logger).toEqual({}); - expect(defaultData.error).toEqual(''); - }); - - let wrapper; - let header; - let username; - let testState; - const mockConfirm = jest.fn(); - const mockResend = jest.fn(); - const mockSignIn = jest.fn(); - const mockSetError = jest.fn(); - - describe('...when it is mounted without props...', () => { - beforeEach(() => { - wrapper = shallowMount(ConfirmSignUp); - testState = null; - }); - - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); - - it('...it should be named ConfirmSignUp', () => { - expect(wrapper.vm.$options.name).toEqual('ConfirmSignUp'); - }); - - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); - - it('...it should have a confirm method', () => { - expect(wrapper.vm.confirm).toBeTruthy(); - }); - - it('...should have a resend method', () => { - expect(wrapper.vm.resend).toBeTruthy(); - }); - - it('...should have a signIn method', () => { - expect(wrapper.vm.signIn).toBeTruthy(); - }); - - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); - - it('...have default options', () => { - expect(wrapper.vm.options.header).toEqual('i18n Confirm Sign Up'); - expect(wrapper.vm.options.username).toEqual(''); - }); - - it('...should set the error property when a valid username is not received', () => { - expect(wrapper.vm.error).toEqual('i18n Valid username not received.'); - }); - - it('...should call Auth.confirmSignUp when confirm method is called', () => { - wrapper.vm.confirm(); - expect(wrapper.vm.$Amplify.Auth.confirmSignUp).toBeCalled(); - }); - - it('...should call Auth.resendSignUp when confirm method is called', () => { - wrapper.vm.resend(); - expect(wrapper.vm.$Amplify.Auth.resendSignUp).toBeCalledWith(wrapper.vm.options.username); - }); - - - it('...should emit authState when signIn method called', () => { - testState = 0; - AmplifyEventBus.$on('authState', (val) => { - if (val === 'signIn') { - testState = 1; - } - }); - wrapper.vm.signIn(); - expect(testState).toEqual(1); - }); - }); - - describe('...when it is mounted with props...', () => { - beforeEach(() => { - header = 'TestHeader'; - username = 'TestUsername'; - wrapper = shallowMount(ConfirmSignUp, { - methods: { - confirm: mockConfirm, - resend: mockResend, - signIn: mockSignIn, - setError: mockSetError, - }, - propsData: { - confirmSignUpConfig: { - username, - header, - }, - }, - }); - }); - - afterEach(() => { - mockConfirm.mockReset(); - mockResend.mockReset(); - mockSignIn.mockReset(); - mockSetError.mockReset(); - }); - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); - - it('...should render the header from props', () => { - const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; - expect(el.textContent).toEqual(header); - }); - - it('...should call confirm when confirm button is clicked', () => { - const el = wrapper.find('button'); - el.trigger('click'); - expect(mockConfirm).toHaveBeenCalled(); - }); - - it('...should call resend when resend is clicked', () => { - const el = wrapper.find(`.${AmplifyUI.hint} > .${AmplifyUI.a}`); - el.trigger('click'); - expect(mockResend).toHaveBeenCalled(); - }); - - it('...should call signIn when signIn button is clicked', () => { - const el = wrapper.find(`span > .${AmplifyUI.a}`); - el.trigger('click'); - expect(mockSignIn).toHaveBeenCalled(); - }); - }); + it('has a mounted hook', () => { + expect(typeof ConfirmSignUp.mounted).toBe('function'); + }); + + it('sets the correct default data', () => { + expect(typeof ConfirmSignUp.data).toBe('function'); + const defaultData = ConfirmSignUp.data(); + expect(defaultData.code).toBe(''); + expect(defaultData.logger).toEqual({}); + expect(defaultData.error).toEqual(''); + }); + + let wrapper; + let header; + let username; + let testState; + const mockConfirm = jest.fn(); + const mockResend = jest.fn(); + const mockSignIn = jest.fn(); + const mockSetError = jest.fn(); + + describe('...when it is mounted without props...', () => { + beforeEach(() => { + wrapper = shallowMount(ConfirmSignUp); + testState = null; + }); + + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); + + it('...it should be named ConfirmSignUp', () => { + expect(wrapper.vm.$options.name).toEqual('ConfirmSignUp'); + }); + + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); + + it('...it should have a confirm method', () => { + expect(wrapper.vm.confirm).toBeTruthy(); + }); + + it('...should have a resend method', () => { + expect(wrapper.vm.resend).toBeTruthy(); + }); + + it('...should have a signIn method', () => { + expect(wrapper.vm.signIn).toBeTruthy(); + }); + + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); + + it('...have default options', () => { + expect(wrapper.vm.options.header).toEqual('i18n Confirm Sign Up'); + expect(wrapper.vm.options.username).toEqual(''); + }); + + it('...should set the error property when a valid username is not received', () => { + expect(wrapper.vm.error).toEqual('i18n Valid username not received.'); + }); + + it('...should call Auth.confirmSignUp when confirm method is called', () => { + wrapper.vm.confirm(); + expect(wrapper.vm.$Amplify.Auth.confirmSignUp).toBeCalled(); + }); + + it('...should call Auth.resendSignUp when confirm method is called', () => { + wrapper.vm.resend(); + expect(wrapper.vm.$Amplify.Auth.resendSignUp).toBeCalledWith( + wrapper.vm.options.username + ); + }); + + it('...should emit authState when signIn method called', () => { + testState = 0; + AmplifyEventBus.$on('authState', val => { + if (val === 'signIn') { + testState = 1; + } + }); + wrapper.vm.signIn(); + expect(testState).toEqual(1); + }); + }); + + describe('...when it is mounted with props...', () => { + beforeEach(() => { + header = 'TestHeader'; + username = 'TestUsername'; + wrapper = shallowMount(ConfirmSignUp, { + methods: { + confirm: mockConfirm, + resend: mockResend, + signIn: mockSignIn, + setError: mockSetError, + }, + propsData: { + confirmSignUpConfig: { + username, + header, + }, + }, + }); + }); + + afterEach(() => { + mockConfirm.mockReset(); + mockResend.mockReset(); + mockSignIn.mockReset(); + mockSetError.mockReset(); + }); + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); + + it('...should render the header from props', () => { + const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; + expect(el.textContent).toEqual(header); + }); + + it('...should call confirm when confirm button is clicked', () => { + const el = wrapper.find('button'); + el.trigger('click'); + expect(mockConfirm).toHaveBeenCalled(); + }); + + it('...should call resend when resend is clicked', () => { + const el = wrapper.find(`.${AmplifyUI.hint} > .${AmplifyUI.a}`); + el.trigger('click'); + expect(mockResend).toHaveBeenCalled(); + }); + + it('...should call signIn when signIn button is clicked', () => { + const el = wrapper.find(`span > .${AmplifyUI.a}`); + el.trigger('click'); + expect(mockSignIn).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/Connect.test.js b/packages/aws-amplify-vue/__tests__/Connect.test.js index 6f859117e92..ef9fad2eb4c 100644 --- a/packages/aws-amplify-vue/__tests__/Connect.test.js +++ b/packages/aws-amplify-vue/__tests__/Connect.test.js @@ -9,23 +9,23 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('Connect', () => { - it('has a beforeMount hook', () => { - expect(typeof Connect.beforeMount).toBe('function'); - }); + it('has a beforeMount hook', () => { + expect(typeof Connect.beforeMount).toBe('function'); + }); - it('has a beforeDestroy book', () => { - expect(typeof Connect.beforeDestroy).toBe('function'); - }); + it('has a beforeDestroy book', () => { + expect(typeof Connect.beforeDestroy).toBe('function'); + }); - it('sets the correct default data', () => { - expect(typeof Connect.data).toBe('function'); - const defaultData = Connect.data(); - expect(defaultData.data).toEqual({}); - expect(defaultData.logger).toEqual({}); - expect(defaultData.errors).toEqual([]); - expect(defaultData.loading).toEqual(false); - expect(defaultData.watchedSubscription).toEqual(null); - expect(defaultData.isMutation).toEqual(false); - expect(defaultData.internalMutation).toEqual(null); - }); -}); \ No newline at end of file + it('sets the correct default data', () => { + expect(typeof Connect.data).toBe('function'); + const defaultData = Connect.data(); + expect(defaultData.data).toEqual({}); + expect(defaultData.logger).toEqual({}); + expect(defaultData.errors).toEqual([]); + expect(defaultData.loading).toEqual(false); + expect(defaultData.watchedSubscription).toEqual(null); + expect(defaultData.isMutation).toEqual(false); + expect(defaultData.internalMutation).toEqual(null); + }); +}); diff --git a/packages/aws-amplify-vue/__tests__/ForgotPassword.test.js b/packages/aws-amplify-vue/__tests__/ForgotPassword.test.js index a49477f3abf..fbcd5fe55bf 100644 --- a/packages/aws-amplify-vue/__tests__/ForgotPassword.test.js +++ b/packages/aws-amplify-vue/__tests__/ForgotPassword.test.js @@ -11,131 +11,137 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('ForgotPassword', () => { - it('has a mounted hook', () => { - expect(typeof ForgotPassword.mounted).toBe('function'); - }); - - it('sets the correct default data', () => { - expect(typeof ForgotPassword.data).toBe('function'); - const defaultData = ForgotPassword.data(); - expect(defaultData.code).toBe(''); - expect(defaultData.logger).toEqual({}); - expect(defaultData.error).toEqual(''); - }); - - let wrapper; - let header; - let testState; - const mockSubmit = jest.fn(); - const mockVerify = jest.fn(); - const mockSignIn = jest.fn(); - const mockSetError = jest.fn(); - - describe('...when it is mounted without props...', () => { - beforeEach(() => { - wrapper = shallowMount(ForgotPassword); - testState = null; - }); - - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); - - it('...it should be named ForgotPassword', () => { - expect(wrapper.vm.$options.name).toEqual('ForgotPassword'); - }); - - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); - - it('...it should have an send method', () => { - expect(wrapper.vm.verify).toBeTruthy(); - }); - - it('...should have a submit method', () => { - expect(wrapper.vm.submit).toBeTruthy(); - }); - - it('...should have a signIn method', () => { - expect(wrapper.vm.signIn).toBeTruthy(); - }); - - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); - - it('...have default options', () => { - expect(wrapper.vm.options.header).toEqual('i18n Reset your password'); - }); - - it('...should call Auth.forgotPassword when submit method is called', () => { - wrapper.vm.submit(); - expect(wrapper.vm.$Amplify.Auth.forgotPassword).toBeCalledWith(wrapper.vm.forgotPwUsername); - }); - - it('...should set the local error variable when setError is called', () => { - wrapper.vm.setError('I messed up'); - expect(wrapper.vm.error).toEqual('i18n I messed up'); - }); - - it('...should call Auth.forgotPasswordSubmit when verify method is called', () => { - wrapper.vm.verify(); - expect(wrapper.vm.$Amplify.Auth.forgotPasswordSubmit).toBeCalledWith(wrapper.vm.forgotPwUsername, - wrapper.vm.password, - wrapper.vm.code); - }); - - it('...should emit authState when signIn method called', () => { - testState = 0; - AmplifyEventBus.$on('authState', (val) => { - if (val === 'signIn') { - testState = 1; - } - }); - wrapper.vm.signIn(); - expect(testState).toEqual(1); - }); - }); - - describe('...when it is mounted with props...', () => { - beforeEach(() => { - header = 'TestHeader'; - wrapper = shallowMount(ForgotPassword, { - methods: { - verify: mockVerify, - submit: mockSubmit, - signIn: mockSignIn, - setError: mockSetError, - }, - propsData: { - forgotPasswordConfig: { - header, - }, - }, - }); - }); - - afterEach(() => { - mockVerify.mockReset(); - mockSubmit.mockReset(); - mockSignIn.mockReset(); - mockSetError.mockReset(); - }); - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); - - it('...should render the header from props', () => { - const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; - expect(el.textContent).toEqual(header); - }); - - it('...should call signIn when signIn button is clicked', () => { - const el = wrapper.find(`.${AmplifyUI.sectionFooterSecondaryContent} > .${AmplifyUI.a}`); - el.trigger('click'); - expect(mockSignIn).toHaveBeenCalled(); - }); - }); + it('has a mounted hook', () => { + expect(typeof ForgotPassword.mounted).toBe('function'); + }); + + it('sets the correct default data', () => { + expect(typeof ForgotPassword.data).toBe('function'); + const defaultData = ForgotPassword.data(); + expect(defaultData.code).toBe(''); + expect(defaultData.logger).toEqual({}); + expect(defaultData.error).toEqual(''); + }); + + let wrapper; + let header; + let testState; + const mockSubmit = jest.fn(); + const mockVerify = jest.fn(); + const mockSignIn = jest.fn(); + const mockSetError = jest.fn(); + + describe('...when it is mounted without props...', () => { + beforeEach(() => { + wrapper = shallowMount(ForgotPassword); + testState = null; + }); + + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); + + it('...it should be named ForgotPassword', () => { + expect(wrapper.vm.$options.name).toEqual('ForgotPassword'); + }); + + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); + + it('...it should have an send method', () => { + expect(wrapper.vm.verify).toBeTruthy(); + }); + + it('...should have a submit method', () => { + expect(wrapper.vm.submit).toBeTruthy(); + }); + + it('...should have a signIn method', () => { + expect(wrapper.vm.signIn).toBeTruthy(); + }); + + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); + + it('...have default options', () => { + expect(wrapper.vm.options.header).toEqual('i18n Reset your password'); + }); + + it('...should call Auth.forgotPassword when submit method is called', () => { + wrapper.vm.submit(); + expect(wrapper.vm.$Amplify.Auth.forgotPassword).toBeCalledWith( + wrapper.vm.forgotPwUsername + ); + }); + + it('...should set the local error variable when setError is called', () => { + wrapper.vm.setError('I messed up'); + expect(wrapper.vm.error).toEqual('i18n I messed up'); + }); + + it('...should call Auth.forgotPasswordSubmit when verify method is called', () => { + wrapper.vm.verify(); + expect(wrapper.vm.$Amplify.Auth.forgotPasswordSubmit).toBeCalledWith( + wrapper.vm.forgotPwUsername, + wrapper.vm.password, + wrapper.vm.code + ); + }); + + it('...should emit authState when signIn method called', () => { + testState = 0; + AmplifyEventBus.$on('authState', val => { + if (val === 'signIn') { + testState = 1; + } + }); + wrapper.vm.signIn(); + expect(testState).toEqual(1); + }); + }); + + describe('...when it is mounted with props...', () => { + beforeEach(() => { + header = 'TestHeader'; + wrapper = shallowMount(ForgotPassword, { + methods: { + verify: mockVerify, + submit: mockSubmit, + signIn: mockSignIn, + setError: mockSetError, + }, + propsData: { + forgotPasswordConfig: { + header, + }, + }, + }); + }); + + afterEach(() => { + mockVerify.mockReset(); + mockSubmit.mockReset(); + mockSignIn.mockReset(); + mockSetError.mockReset(); + }); + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); + + it('...should render the header from props', () => { + const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; + expect(el.textContent).toEqual(header); + }); + + it('...should call signIn when signIn button is clicked', () => { + const el = wrapper.find( + `.${AmplifyUI.sectionFooterSecondaryContent} > .${AmplifyUI.a}` + ); + el.trigger('click'); + expect(mockSignIn).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/GetUser.test.js b/packages/aws-amplify-vue/__tests__/GetUser.test.js index 51c99a196a9..b0f36b0587e 100644 --- a/packages/aws-amplify-vue/__tests__/GetUser.test.js +++ b/packages/aws-amplify-vue/__tests__/GetUser.test.js @@ -2,32 +2,34 @@ import getUser from '../src/services/getUser'; import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; describe('GetUser Service...', () => { - it('...should exist', () => { - expect(getUser).toBeTruthy(); - }); + it('...should exist', () => { + expect(getUser).toBeTruthy(); + }); - it('...should call Auth.currentAuthenticatedUser', () => { - getUser(AmplifyMocks); - expect(AmplifyMocks.Auth.currentAuthenticatedUser).toBeCalled(); - }); + it('...should call Auth.currentAuthenticatedUser', () => { + getUser(AmplifyMocks); + expect(AmplifyMocks.Auth.currentAuthenticatedUser).toBeCalled(); + }); - it('...should return null if no user', async () => { - const tempMock = Object.assign(AmplifyMocks, { - Auth: { - currentAuthenticatedUser: jest.fn(() => Promise.resolve(null)), - }, - }); - const res = await getUser(tempMock) - expect(res).toEqual(null); - }); + it('...should return null if no user', async () => { + const tempMock = Object.assign(AmplifyMocks, { + Auth: { + currentAuthenticatedUser: jest.fn(() => Promise.resolve(null)), + }, + }); + const res = await getUser(tempMock); + expect(res).toEqual(null); + }); - it('...should returnan error if currentAuthenticatedUser rejects', async () => { - const tempMockFail = Object.assign(AmplifyMocks, { - Auth: { - currentAuthenticatedUser: jest.fn(() => Promise.reject(new Error('I rejected'))), - }, - }); - const res = await getUser(tempMockFail) - expect(res).toBeInstanceOf(Error); - }); + it('...should returnan error if currentAuthenticatedUser rejects', async () => { + const tempMockFail = Object.assign(AmplifyMocks, { + Auth: { + currentAuthenticatedUser: jest.fn(() => + Promise.reject(new Error('I rejected')) + ), + }, + }); + const res = await getUser(tempMockFail); + expect(res).toBeInstanceOf(Error); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/PhoneField.test.js b/packages/aws-amplify-vue/__tests__/PhoneField.test.js index 8260a257d77..c9af005731b 100644 --- a/packages/aws-amplify-vue/__tests__/PhoneField.test.js +++ b/packages/aws-amplify-vue/__tests__/PhoneField.test.js @@ -10,37 +10,41 @@ import countries from '../src/assets/countries'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('PhoneField', () => { - let wrapper = null; - const mockPhoneNumberChanged = jest.fn(); - beforeEach(() => { - wrapper = shallowMount(PhoneField, { - methods: { - emitPhoneNumberChanged: mockPhoneNumberChanged, - } - }); - }); + let wrapper = null; + const mockPhoneNumberChanged = jest.fn(); + beforeEach(() => { + wrapper = shallowMount(PhoneField, { + methods: { + emitPhoneNumberChanged: mockPhoneNumberChanged, + }, + }); + }); - afterEach(() => { - mockPhoneNumberChanged.mockReset(); - - }); - - it('sets the correct default data', () => { - expect(typeof PhoneField.data).toBe('function'); - const defaultData = PhoneField.data(); - expect(defaultData.countryCode).toEqual('1'); - expect(defaultData.local_phone_number).toEqual(''); - expect(defaultData.countries).toEqual(countries); - }); + afterEach(() => { + mockPhoneNumberChanged.mockReset(); + }); + it('sets the correct default data', () => { + expect(typeof PhoneField.data).toBe('function'); + const defaultData = PhoneField.data(); + expect(defaultData.countryCode).toEqual('1'); + expect(defaultData.local_phone_number).toEqual(''); + expect(defaultData.countries).toEqual(countries); + }); - it('emit phone number changed when country code changed', () => { - wrapper.findAll('select').at(0).trigger('change') - expect(mockPhoneNumberChanged).toBeCalled(); - }); + it('emit phone number changed when country code changed', () => { + wrapper + .findAll('select') + .at(0) + .trigger('change'); + expect(mockPhoneNumberChanged).toBeCalled(); + }); - it('emit phone number changed when local phone numer changed', () => { - wrapper.findAll('input').at(0).trigger('keyup') - expect(mockPhoneNumberChanged).toBeCalled(); - }); -}); \ No newline at end of file + it('emit phone number changed when local phone numer changed', () => { + wrapper + .findAll('input') + .at(0) + .trigger('keyup'); + expect(mockPhoneNumberChanged).toBeCalled(); + }); +}); diff --git a/packages/aws-amplify-vue/__tests__/PhotoPicker.test.js b/packages/aws-amplify-vue/__tests__/PhotoPicker.test.js index 04f36a4457a..d2d9e9ef870 100644 --- a/packages/aws-amplify-vue/__tests__/PhotoPicker.test.js +++ b/packages/aws-amplify-vue/__tests__/PhotoPicker.test.js @@ -10,146 +10,156 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('PhotoPicker', () => { - it('has a mounted hook', () => { - expect(typeof PhotoPicker.mounted).toBe('function'); - }); - - it('sets the correct default data', () => { - expect(typeof PhotoPicker.data).toBe('function'); - const defaultData = PhotoPicker.data(); - expect(defaultData.file).toBe(null); - expect(defaultData.s3ImagePath).toEqual(''); - expect(defaultData.photoUrl).toEqual(''); - expect(defaultData.logger).toEqual({}); - expect(defaultData.error).toEqual(''); - }); - - let wrapper; - let header; - let title; - let accept; - const mockUpload = jest.fn(); - const mockPick = jest.fn(); - const mockCompleteFileUpload = jest.fn(); - const mockSetError = jest.fn(); - - describe('...when it is mounted without props...', () => { - beforeEach(() => { - wrapper = shallowMount(PhotoPicker); - }); - - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); - - it('...it should be named PhotoPicker', () => { - expect(wrapper.vm.$options.name).toEqual('PhotoPicker'); - }); - - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); - - it('...it should have a pick method', () => { - expect(wrapper.vm.pick).toBeTruthy(); - }); - - it('...it should have an upload method', () => { - expect(wrapper.vm.upload).toBeTruthy(); - }); - - it('...it should have a completeFileUpload method', () => { - expect(wrapper.vm.completeFileUpload).toBeTruthy(); - }); - - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); - - it('...have default options', () => { - expect(wrapper.vm.options.header).toEqual('i18n File Upload'); - expect(wrapper.vm.options.title).toEqual('i18n Upload'); - expect(wrapper.vm.options.accept).toEqual('*/*'); - }); - }); - - describe('...when the methods are not mocked...', () => { - wrapper = mount(PhotoPicker); - it('...should have a upload method that calls Amplify.Auth.PhotoPicker', () => { - wrapper.vm.s3ImagePath = 'testPath'; - wrapper.vm.file = { type: 'fakeFile' }; - wrapper.vm.options.storageOptions = { level: 'private', contentType: 'fakeType' }; - wrapper.vm.upload(); - expect(wrapper.vm.$Amplify.Storage.put) - .toHaveBeenCalledWith('testPath', { type: 'fakeFile' }, { level: 'private', contentType: 'fakeType' }, ); - }); - }); - - describe('...when it is mounted with props...', () => { - beforeEach(() => { - header = 'Give me files'; - title = 'Click me'; - accept = 'image/*'; - wrapper = shallowMount(PhotoPicker, { - methods: { - upload: mockUpload, - pick: mockPick, - completeFileUpload: mockCompleteFileUpload, - setError: mockSetError, - }, - propsData: { - photoPickerConfig: { - header, - title, - accept, - path: 'url', - }, - }, - }); - }); - - afterEach(() => { - wrapper.vm.file = null; - }); - - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); - - it('...should render the header from props', () => { - const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; - expect(el.textContent).toEqual(header); - }); - - it('...upload button should not appear when file is not picked', () => { - const el = wrapper.find('button').element; - expect(el).toBeFalsy(); - }); - - it('...should get the passed upload button text', () => { - wrapper.vm.file = { foo: 'bar' }; - const text = wrapper.find('button').text(); - expect(text).toEqual(title); - }); - - it('...should call completeFileUpload when upload is clicked', () => { - wrapper.vm.upload(); - wrapper.vm.file = { foo: 'bar' }; - wrapper.vm.s3ImageFile = 'testImage'; - wrapper.vm.$Amplify.Storage.put('testPath', { type: 'fakeFile' }, { contentType: 'fakeFile' }) - .then((res) => { - expect(mockCompleteFileUpload).toHaveBeenCalledWith(res.key); - expect(wrapper.vm.file).toBe(null); - expect(wrapper.vm.s3ImageFile).toBe(null); - }) - .catch(e => e); - }); - - it('...should call pick when file input is activated', () => { - const el = wrapper.find('input'); - el.trigger('change'); - expect(mockPick).toBeCalled(); - }); - }); + it('has a mounted hook', () => { + expect(typeof PhotoPicker.mounted).toBe('function'); + }); + + it('sets the correct default data', () => { + expect(typeof PhotoPicker.data).toBe('function'); + const defaultData = PhotoPicker.data(); + expect(defaultData.file).toBe(null); + expect(defaultData.s3ImagePath).toEqual(''); + expect(defaultData.photoUrl).toEqual(''); + expect(defaultData.logger).toEqual({}); + expect(defaultData.error).toEqual(''); + }); + + let wrapper; + let header; + let title; + let accept; + const mockUpload = jest.fn(); + const mockPick = jest.fn(); + const mockCompleteFileUpload = jest.fn(); + const mockSetError = jest.fn(); + + describe('...when it is mounted without props...', () => { + beforeEach(() => { + wrapper = shallowMount(PhotoPicker); + }); + + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); + + it('...it should be named PhotoPicker', () => { + expect(wrapper.vm.$options.name).toEqual('PhotoPicker'); + }); + + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); + + it('...it should have a pick method', () => { + expect(wrapper.vm.pick).toBeTruthy(); + }); + + it('...it should have an upload method', () => { + expect(wrapper.vm.upload).toBeTruthy(); + }); + + it('...it should have a completeFileUpload method', () => { + expect(wrapper.vm.completeFileUpload).toBeTruthy(); + }); + + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); + + it('...have default options', () => { + expect(wrapper.vm.options.header).toEqual('i18n File Upload'); + expect(wrapper.vm.options.title).toEqual('i18n Upload'); + expect(wrapper.vm.options.accept).toEqual('*/*'); + }); + }); + + describe('...when the methods are not mocked...', () => { + wrapper = mount(PhotoPicker); + it('...should have a upload method that calls Amplify.Auth.PhotoPicker', () => { + wrapper.vm.s3ImagePath = 'testPath'; + wrapper.vm.file = { type: 'fakeFile' }; + wrapper.vm.options.storageOptions = { + level: 'private', + contentType: 'fakeType', + }; + wrapper.vm.upload(); + expect(wrapper.vm.$Amplify.Storage.put).toHaveBeenCalledWith( + 'testPath', + { type: 'fakeFile' }, + { level: 'private', contentType: 'fakeType' } + ); + }); + }); + + describe('...when it is mounted with props...', () => { + beforeEach(() => { + header = 'Give me files'; + title = 'Click me'; + accept = 'image/*'; + wrapper = shallowMount(PhotoPicker, { + methods: { + upload: mockUpload, + pick: mockPick, + completeFileUpload: mockCompleteFileUpload, + setError: mockSetError, + }, + propsData: { + photoPickerConfig: { + header, + title, + accept, + path: 'url', + }, + }, + }); + }); + + afterEach(() => { + wrapper.vm.file = null; + }); + + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); + + it('...should render the header from props', () => { + const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; + expect(el.textContent).toEqual(header); + }); + + it('...upload button should not appear when file is not picked', () => { + const el = wrapper.find('button').element; + expect(el).toBeFalsy(); + }); + + it('...should get the passed upload button text', () => { + wrapper.vm.file = { foo: 'bar' }; + const text = wrapper.find('button').text(); + expect(text).toEqual(title); + }); + + it('...should call completeFileUpload when upload is clicked', () => { + wrapper.vm.upload(); + wrapper.vm.file = { foo: 'bar' }; + wrapper.vm.s3ImageFile = 'testImage'; + wrapper.vm.$Amplify.Storage.put( + 'testPath', + { type: 'fakeFile' }, + { contentType: 'fakeFile' } + ) + .then(res => { + expect(mockCompleteFileUpload).toHaveBeenCalledWith(res.key); + expect(wrapper.vm.file).toBe(null); + expect(wrapper.vm.s3ImageFile).toBe(null); + }) + .catch(e => e); + }); + + it('...should call pick when file input is activated', () => { + const el = wrapper.find('input'); + el.trigger('change'); + expect(mockPick).toBeCalled(); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/RequireNewPassword.test.js b/packages/aws-amplify-vue/__tests__/RequireNewPassword.test.js index 53a7a2fedbf..7fe5562462a 100644 --- a/packages/aws-amplify-vue/__tests__/RequireNewPassword.test.js +++ b/packages/aws-amplify-vue/__tests__/RequireNewPassword.test.js @@ -7,105 +7,107 @@ import AmplifyEventBus from '../src/events/AmplifyEventBus'; import AmplifyPlugin from '../src/plugins/AmplifyPlugin'; import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; /* eslint-enable */ - Vue.use(AmplifyPlugin, AmplifyMocks); - describe('RequireNewPassword', () => { - it('has a mounted hook', () => { - expect(typeof RequireNewPassword.mounted).toBe('function'); - }); - it('sets the correct default data', () => { - expect(typeof RequireNewPassword.data).toBe('function'); - const defaultData = RequireNewPassword.data(); - expect(defaultData.logger).toEqual({}); - expect(defaultData.error).toEqual(''); - }); - let wrapper; - let header; - let testState; - const mockSubmit = jest.fn(); - const mockVerify = jest.fn(); - const mockSignIn = jest.fn(); - const mockSetError = jest.fn(); - describe('...when it is mounted without props...', () => { - beforeEach(() => { - wrapper = shallowMount(RequireNewPassword); - testState = null; - }); - it('...it should use the amplify plugin with passed modules', () => { - console.log('wrapper', wrapper) - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); - it('...it should be named RequireNewPassword', () => { - expect(wrapper.vm.$options.name).toEqual('RequireNewPassword'); - }); - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); - it('...it should have a change method', () => { - expect(wrapper.vm.change).toBeTruthy(); - }); - it('...should have a checkContact method', () => { - expect(wrapper.vm.checkContact).toBeTruthy(); - }); - it('...should have a signIn method', () => { - expect(wrapper.vm.signIn).toBeTruthy(); - }); - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); - it('...have default options', () => { - expect(wrapper.vm.options.header).toEqual('i18n Enter new password'); - }); - it('...should call Auth.completeNewPassword when change method is called', () => { - wrapper.vm.change(); - expect(wrapper.vm.$Amplify.Auth.completeNewPassword).toBeCalled(); - }); - it('...should set the local error variable when setError is called', () => { - wrapper.vm.setError('I messed up'); - expect(wrapper.vm.error).toEqual('i18n I messed up'); - }); - it('...should call Auth.forgotPasswordSubmit when checkContact method is called', () => { - wrapper.vm.checkContact(); - expect(wrapper.vm.$Amplify.Auth.verifiedContact).toBeCalled(); - }); - }); - describe('...when it is mounted with props...', () => { - beforeEach(() => { - header = 'TestHeader'; - wrapper = shallowMount(RequireNewPassword, { - methods: { - verify: mockVerify, - submit: mockSubmit, - signIn: mockSignIn, - setError: mockSetError, - }, - propsData: { - requireNewPasswordConfig: { - header, - user: { - challengeParam: {} - } - }, - }, - }); - }); - afterEach(() => { - mockVerify.mockReset(); - mockSubmit.mockReset(); - mockSignIn.mockReset(); - mockSetError.mockReset(); - }); - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); - it('...should render the header from props', () => { - const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; - expect(el.textContent).toEqual(header); - }); - it('...should call signIn when signIn button is clicked', () => { - const el = wrapper.find(`.${AmplifyUI.sectionFooterSecondaryContent} > .${AmplifyUI.a}`); - el.trigger('click'); - expect(mockSignIn).toHaveBeenCalled(); - }); - }); -}); \ No newline at end of file +Vue.use(AmplifyPlugin, AmplifyMocks); +describe('RequireNewPassword', () => { + it('has a mounted hook', () => { + expect(typeof RequireNewPassword.mounted).toBe('function'); + }); + it('sets the correct default data', () => { + expect(typeof RequireNewPassword.data).toBe('function'); + const defaultData = RequireNewPassword.data(); + expect(defaultData.logger).toEqual({}); + expect(defaultData.error).toEqual(''); + }); + let wrapper; + let header; + let testState; + const mockSubmit = jest.fn(); + const mockVerify = jest.fn(); + const mockSignIn = jest.fn(); + const mockSetError = jest.fn(); + describe('...when it is mounted without props...', () => { + beforeEach(() => { + wrapper = shallowMount(RequireNewPassword); + testState = null; + }); + it('...it should use the amplify plugin with passed modules', () => { + console.log('wrapper', wrapper); + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); + it('...it should be named RequireNewPassword', () => { + expect(wrapper.vm.$options.name).toEqual('RequireNewPassword'); + }); + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); + it('...it should have a change method', () => { + expect(wrapper.vm.change).toBeTruthy(); + }); + it('...should have a checkContact method', () => { + expect(wrapper.vm.checkContact).toBeTruthy(); + }); + it('...should have a signIn method', () => { + expect(wrapper.vm.signIn).toBeTruthy(); + }); + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); + it('...have default options', () => { + expect(wrapper.vm.options.header).toEqual('i18n Enter new password'); + }); + it('...should call Auth.completeNewPassword when change method is called', () => { + wrapper.vm.change(); + expect(wrapper.vm.$Amplify.Auth.completeNewPassword).toBeCalled(); + }); + it('...should set the local error variable when setError is called', () => { + wrapper.vm.setError('I messed up'); + expect(wrapper.vm.error).toEqual('i18n I messed up'); + }); + it('...should call Auth.forgotPasswordSubmit when checkContact method is called', () => { + wrapper.vm.checkContact(); + expect(wrapper.vm.$Amplify.Auth.verifiedContact).toBeCalled(); + }); + }); + describe('...when it is mounted with props...', () => { + beforeEach(() => { + header = 'TestHeader'; + wrapper = shallowMount(RequireNewPassword, { + methods: { + verify: mockVerify, + submit: mockSubmit, + signIn: mockSignIn, + setError: mockSetError, + }, + propsData: { + requireNewPasswordConfig: { + header, + user: { + challengeParam: {}, + }, + }, + }, + }); + }); + afterEach(() => { + mockVerify.mockReset(); + mockSubmit.mockReset(); + mockSignIn.mockReset(); + mockSetError.mockReset(); + }); + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); + it('...should render the header from props', () => { + const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; + expect(el.textContent).toEqual(header); + }); + it('...should call signIn when signIn button is clicked', () => { + const el = wrapper.find( + `.${AmplifyUI.sectionFooterSecondaryContent} > .${AmplifyUI.a}` + ); + el.trigger('click'); + expect(mockSignIn).toHaveBeenCalled(); + }); + }); +}); diff --git a/packages/aws-amplify-vue/__tests__/S3Album.test.js b/packages/aws-amplify-vue/__tests__/S3Album.test.js index 88cb8033cc1..ce71e66d7ac 100644 --- a/packages/aws-amplify-vue/__tests__/S3Album.test.js +++ b/packages/aws-amplify-vue/__tests__/S3Album.test.js @@ -12,77 +12,77 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('S3Album', () => { - let wrapper; - const mockGetImages = jest.fn(); - const mockPushImage = jest.fn(); - const mockSetError = jest.fn(); + let wrapper; + const mockGetImages = jest.fn(); + const mockPushImage = jest.fn(); + const mockSetError = jest.fn(); - describe('...when it is mounted with props but methods not mocked...', () => { - beforeEach(() => { - wrapper = shallowMount(S3Album, { - propsData: { - path: 'fakePath' - }, - }); - }); + describe('...when it is mounted with props but methods not mocked...', () => { + beforeEach(() => { + wrapper = shallowMount(S3Album, { + propsData: { + path: 'fakePath', + }, + }); + }); - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); - it('...it should be named S3Album', () => { - expect(wrapper.vm.$options.name).toEqual('S3Album'); - }); + it('...it should be named S3Album', () => { + expect(wrapper.vm.$options.name).toEqual('S3Album'); + }); - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); - it('...it should have a getImages method', () => { - expect(wrapper.vm.getImages).toBeTruthy(); - }); + it('...it should have a getImages method', () => { + expect(wrapper.vm.getImages).toBeTruthy(); + }); - it('...it should have a pushImage method', () => { - expect(wrapper.vm.pushImage).toBeTruthy(); - }); + it('...it should have a pushImage method', () => { + expect(wrapper.vm.pushImage).toBeTruthy(); + }); - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); - it('...should call $Amplify.Storage.list when getImages is called', () => { - expect(wrapper.vm.$Amplify.Storage.list).toHaveBeenCalled(); - }); - }); + it('...should call $Amplify.Storage.list when getImages is called', () => { + expect(wrapper.vm.$Amplify.Storage.list).toHaveBeenCalled(); + }); + }); - describe('...when it is mounted with props...', () => { - beforeEach(() => { - wrapper = shallowMount(S3Album, { - methods: { - getImages: mockGetImages, - pushImage: mockPushImage, - setError: mockSetError, - }, - propsData: { - path: 'testPath', - }, - }); - }); + describe('...when it is mounted with props...', () => { + beforeEach(() => { + wrapper = shallowMount(S3Album, { + methods: { + getImages: mockGetImages, + pushImage: mockPushImage, + setError: mockSetError, + }, + propsData: { + path: 'testPath', + }, + }); + }); - afterEach(() => { - mockGetImages.mockReset(); - mockPushImage.mockReset(); - mockSetError.mockReset(); - }); + afterEach(() => { + mockGetImages.mockReset(); + mockPushImage.mockReset(); + mockSetError.mockReset(); + }); - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); - it('...should call pushImage when fileUpload event occurs', () => { - AmplifyEventBus.$emit('fileUpload', { foo: 'bar' }); - expect(mockPushImage).toHaveBeenCalled(); - }); - }); + it('...should call pushImage when fileUpload event occurs', () => { + AmplifyEventBus.$emit('fileUpload', { foo: 'bar' }); + expect(mockPushImage).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/S3Image.test.js b/packages/aws-amplify-vue/__tests__/S3Image.test.js index c6368575d15..0c7d534cfb8 100644 --- a/packages/aws-amplify-vue/__tests__/S3Image.test.js +++ b/packages/aws-amplify-vue/__tests__/S3Image.test.js @@ -12,86 +12,86 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('S3Image', () => { - let wrapper; - const mockGetImage = jest.fn(); - const mockBlowUp = jest.fn(); - const mockSetError = jest.fn(); + let wrapper; + const mockGetImage = jest.fn(); + const mockBlowUp = jest.fn(); + const mockSetError = jest.fn(); - describe('...when it is mounted with props but methods not mocked...', () => { - beforeEach(() => { - global.open = jest.fn(); - wrapper = shallowMount(S3Image, { - propsData: { - path: 'testPath', - }, - }); - }); + describe('...when it is mounted with props but methods not mocked...', () => { + beforeEach(() => { + global.open = jest.fn(); + wrapper = shallowMount(S3Image, { + propsData: { + path: 'testPath', + }, + }); + }); - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); - it('...it should be named S3Image', () => { - expect(wrapper.vm.$options.name).toEqual('S3Image'); - }); + it('...it should be named S3Image', () => { + expect(wrapper.vm.$options.name).toEqual('S3Image'); + }); - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); - it('...it should have a getImage method', () => { - expect(wrapper.vm.getImage).toBeTruthy(); - }); + it('...it should have a getImage method', () => { + expect(wrapper.vm.getImage).toBeTruthy(); + }); - it('...it should have a blowUp method', () => { - expect(wrapper.vm.blowUp).toBeTruthy(); - }); + it('...it should have a blowUp method', () => { + expect(wrapper.vm.blowUp).toBeTruthy(); + }); - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); - it('...should call $Amplify.Storage.get when getImages is called with imagePath', () => { - wrapper.vm.imagePath = 'testPath'; - wrapper.vm.getImage(); - expect(wrapper.vm.$Amplify.Storage.get).toHaveBeenCalled(); - }); + it('...should call $Amplify.Storage.get when getImages is called with imagePath', () => { + wrapper.vm.imagePath = 'testPath'; + wrapper.vm.getImage(); + expect(wrapper.vm.$Amplify.Storage.get).toHaveBeenCalled(); + }); - it('...should not call window.open when blowUp is called', () => { - wrapper.vm.blowUp(); - expect(global.open).toHaveBeenCalled(); - }); - }); + it('...should not call window.open when blowUp is called', () => { + wrapper.vm.blowUp(); + expect(global.open).toHaveBeenCalled(); + }); + }); - describe('...when it is mounted with props...', () => { - beforeEach(() => { - wrapper = shallowMount(S3Image, { - methods: { - blowUp: mockBlowUp, - getImage: mockGetImage, - setError: mockSetError, - }, - propsData: { - path: 'testPath', - }, - }); - }); + describe('...when it is mounted with props...', () => { + beforeEach(() => { + wrapper = shallowMount(S3Image, { + methods: { + blowUp: mockBlowUp, + getImage: mockGetImage, + setError: mockSetError, + }, + propsData: { + path: 'testPath', + }, + }); + }); - afterEach(() => { - mockGetImage.mockReset(); - mockBlowUp.mockReset(); - mockSetError.mockReset(); - }); + afterEach(() => { + mockGetImage.mockReset(); + mockBlowUp.mockReset(); + mockSetError.mockReset(); + }); - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); - it('...should call blowUp when image element is clicked', () => { - const el = wrapper.find('img'); - el.trigger('click'); - expect(mockBlowUp).toHaveBeenCalled(); - }); - }); + it('...should call blowUp when image element is clicked', () => { + const el = wrapper.find('img'); + el.trigger('click'); + expect(mockBlowUp).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/SetMFA.test.js b/packages/aws-amplify-vue/__tests__/SetMFA.test.js index 92799355e52..54dcbf5956d 100644 --- a/packages/aws-amplify-vue/__tests__/SetMFA.test.js +++ b/packages/aws-amplify-vue/__tests__/SetMFA.test.js @@ -9,213 +9,218 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('SetMFA', () => { - it('has a mounted hook', () => { - expect(typeof SetMFA.mounted).toBe('function'); - }); - - it('sets the correct default data', () => { - expect(typeof SetMFA.data).toBe('function'); - const defaultData = SetMFA.data(); - expect(defaultData.user).toBe(null); - expect(defaultData.mfaPreference).toBe(null); - expect(defaultData.token).toBe(''); - expect(defaultData.displayTotpSetup).toBe(false); - expect(defaultData.logger).toEqual({}); - expect(defaultData.error).toEqual(''); - }); - - let wrapper; - let testText; - const mockSetup = jest.fn(); - const mockSetUser = jest.fn(); - const mockSetMFA = jest.fn(); - const mockVerifyTotpToken = jest.fn(); - const mockSetError = jest.fn(); - - describe('...when it is mounted without props...', () => { - beforeEach(() => { - wrapper = shallowMount(SetMFA); - }); - - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); - - it('...it should be named SetMFA', () => { - expect(wrapper.vm.$options.name).toEqual('SetMfa'); - }); - - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); - - it('...it should have an setup method', () => { - expect(wrapper.vm.setup).toBeTruthy(); - }); - - it('...should have a setUser method', () => { - expect(wrapper.vm.setUser).toBeTruthy(); - }); - - it('...should have a setMFA method', () => { - expect(wrapper.vm.setMFA).toBeTruthy(); - }); - - it('...should have a verifyTotpToken method', () => { - expect(wrapper.vm.verifyTotpToken).toBeTruthy(); - }); - - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); - - it('...have default options', () => { - expect(wrapper.vm.options.header).toEqual('Multifactor Authentication Preference'); - }); - it('...should call Auth.setPreferredMFA when setMFA function is called', () => { - wrapper.vm.setMFA(); - expect(wrapper.vm.$Amplify.Auth.setPreferredMFA).toHaveBeenCalledTimes(1); - }); - it('...should call Auth.verifyTotpToken when verifyTotpToken function is called', () => { - wrapper.vm.verifyTotpToken(); - expect(wrapper.vm.$Amplify.Auth.verifyTotpToken).toHaveBeenCalledTimes(1); - }); - }); - - describe('...whent it is mounted with props but methods unmocked', () => { - beforeEach(() => { - wrapper = shallowMount(SetMFA, { - propsData: { - mfaConfig: { - header: testText, - mfaDescription: testText, - tokenInstructions: testText, - smsDescription: testText, - totpDescription: testText, - noMfaDescription: testText, - mfaTypes: [], - }, - }, - }); - }); - it('...should call Auth.setupTOTP when setup function is called', async () => { - wrapper.vm.setup(); - let testToken = `otpauth://totp/AWSCognito:${wrapper.vm.user.username}?secret=gibberish&issuer=AWSCognito`; - await expect(wrapper.vm.$Amplify.Auth.setupTOTP).toBeCalledWith(wrapper.vm.user); - expect(wrapper.vm.token).toEqual(testToken); - }); - }); - - describe('...when it is mounted with props...', () => { - beforeEach(() => { - testText = 'TestText'; - wrapper = shallowMount(SetMFA, { - methods: { - setup: mockSetup, - setUser: mockSetUser, - setMFA: mockSetMFA, - verifyTotpToken: mockVerifyTotpToken, - setError: mockSetError, - }, - propsData: { - mfaConfig: { - header: testText, - mfaDescription: testText, - tokenInstructions: testText, - smsDescription: testText, - totpDescription: testText, - noMfaDescription: testText, - mfaTypes: [], - }, - }, - }); - }); - - afterEach(() => { - mockSetup.mockReset(); - mockSetUser.mockReset(); - mockSetMFA.mockReset(); - mockVerifyTotpToken.mockReset(); - mockSetError.mockReset(); - }); - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); - - it('...should render the header from props', () => { - const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; - expect(el.firstChild.textContent.trim()).toEqual(testText); - }); - - it('...should render the mfaDescription from props', () => { - const el = wrapper.find(`.${AmplifyUI.sectionHeader} > div`).element; - expect(el.textContent.trim()).toEqual(testText); - }); - - it('...should not render the sms radio button if sms is not in mfaTypes', () => { - const el = wrapper.find(`.${AmplifyUI.sectionHeader} > div`).element; - expect(el.textContent.trim()).toEqual(testText); - }); - - it('...should call setUser on mount', () => { - expect(mockSetUser).toHaveBeenCalled(); - }); - - it('...should display setMFA button if !displayTotpSetup', () => { - const el = wrapper.find('#setMfa').exists; - expect(el).toBeTruthy(); - }); - - it('...should not display setMFA button if displayTotpSetup', () => { - wrapper.vm.token = 'token'; - wrapper.vm.displayTotpSetup = true; - const el = wrapper.find('#setMFA').element; - expect(el).toBeFalsy(); - }); - - it('...should call setMFA on setMFA button click', () => { - const el = wrapper.find(`.${AmplifyUI.sectionFooterPrimaryContent} > button`); - el.trigger('click'); - expect(mockSetMFA).toHaveBeenCalled(); - }); - - - it('...should display verifyTotpToken button if displayTotpSetup', () => { - wrapper.vm.token = 'token'; - wrapper.vm.displayTotpSetup = true; - const el = wrapper.find('#verify').exists; - expect(el).toBeTruthy(); - }); - - it('...should not display verifyTotpToken button if !displayTotpSetup', () => { - const el = wrapper.find('#verify').element; - expect(el).toBeFalsy(); - }); - - it('...should call verifyTotpToken on verifyTotpToken button click', () => { - wrapper.vm.token = 'token'; - wrapper.vm.displayTotpSetup = true; - const el = wrapper.find('#verify'); - el.trigger('click'); - expect(mockVerifyTotpToken).toHaveBeenCalled(); - }); - - it('...setup should be called when mfaPreference changes', () => { - wrapper.vm.mfaPreference = 'TOTP'; - expect(mockSetup).toHaveBeenCalled(); - }); - - it('...Qrcode element should not exist if displayTotpSetup is false', () => { - const qr = wrapper.find(`.${AmplifyUI.totpQrcode}`).exists(); - expect(qr).toBeFalsy(); - }); - - it('...vQrcode element should exist if displayTotpSetup is true', () => { - wrapper.vm.token = 'testtoken'; - wrapper.vm.displayTotpSetup = true; - const qr = wrapper.find(`.${AmplifyUI.totpQrcode}`).exists(); - expect(qr).toBeTruthy(); - }); - }); + it('has a mounted hook', () => { + expect(typeof SetMFA.mounted).toBe('function'); + }); + + it('sets the correct default data', () => { + expect(typeof SetMFA.data).toBe('function'); + const defaultData = SetMFA.data(); + expect(defaultData.user).toBe(null); + expect(defaultData.mfaPreference).toBe(null); + expect(defaultData.token).toBe(''); + expect(defaultData.displayTotpSetup).toBe(false); + expect(defaultData.logger).toEqual({}); + expect(defaultData.error).toEqual(''); + }); + + let wrapper; + let testText; + const mockSetup = jest.fn(); + const mockSetUser = jest.fn(); + const mockSetMFA = jest.fn(); + const mockVerifyTotpToken = jest.fn(); + const mockSetError = jest.fn(); + + describe('...when it is mounted without props...', () => { + beforeEach(() => { + wrapper = shallowMount(SetMFA); + }); + + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); + + it('...it should be named SetMFA', () => { + expect(wrapper.vm.$options.name).toEqual('SetMfa'); + }); + + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); + + it('...it should have an setup method', () => { + expect(wrapper.vm.setup).toBeTruthy(); + }); + + it('...should have a setUser method', () => { + expect(wrapper.vm.setUser).toBeTruthy(); + }); + + it('...should have a setMFA method', () => { + expect(wrapper.vm.setMFA).toBeTruthy(); + }); + + it('...should have a verifyTotpToken method', () => { + expect(wrapper.vm.verifyTotpToken).toBeTruthy(); + }); + + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); + + it('...have default options', () => { + expect(wrapper.vm.options.header).toEqual( + 'Multifactor Authentication Preference' + ); + }); + it('...should call Auth.setPreferredMFA when setMFA function is called', () => { + wrapper.vm.setMFA(); + expect(wrapper.vm.$Amplify.Auth.setPreferredMFA).toHaveBeenCalledTimes(1); + }); + it('...should call Auth.verifyTotpToken when verifyTotpToken function is called', () => { + wrapper.vm.verifyTotpToken(); + expect(wrapper.vm.$Amplify.Auth.verifyTotpToken).toHaveBeenCalledTimes(1); + }); + }); + + describe('...whent it is mounted with props but methods unmocked', () => { + beforeEach(() => { + wrapper = shallowMount(SetMFA, { + propsData: { + mfaConfig: { + header: testText, + mfaDescription: testText, + tokenInstructions: testText, + smsDescription: testText, + totpDescription: testText, + noMfaDescription: testText, + mfaTypes: [], + }, + }, + }); + }); + it('...should call Auth.setupTOTP when setup function is called', async () => { + wrapper.vm.setup(); + let testToken = `otpauth://totp/AWSCognito:${wrapper.vm.user.username}?secret=gibberish&issuer=AWSCognito`; + await expect(wrapper.vm.$Amplify.Auth.setupTOTP).toBeCalledWith( + wrapper.vm.user + ); + expect(wrapper.vm.token).toEqual(testToken); + }); + }); + + describe('...when it is mounted with props...', () => { + beforeEach(() => { + testText = 'TestText'; + wrapper = shallowMount(SetMFA, { + methods: { + setup: mockSetup, + setUser: mockSetUser, + setMFA: mockSetMFA, + verifyTotpToken: mockVerifyTotpToken, + setError: mockSetError, + }, + propsData: { + mfaConfig: { + header: testText, + mfaDescription: testText, + tokenInstructions: testText, + smsDescription: testText, + totpDescription: testText, + noMfaDescription: testText, + mfaTypes: [], + }, + }, + }); + }); + + afterEach(() => { + mockSetup.mockReset(); + mockSetUser.mockReset(); + mockSetMFA.mockReset(); + mockVerifyTotpToken.mockReset(); + mockSetError.mockReset(); + }); + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); + + it('...should render the header from props', () => { + const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; + expect(el.firstChild.textContent.trim()).toEqual(testText); + }); + + it('...should render the mfaDescription from props', () => { + const el = wrapper.find(`.${AmplifyUI.sectionHeader} > div`).element; + expect(el.textContent.trim()).toEqual(testText); + }); + + it('...should not render the sms radio button if sms is not in mfaTypes', () => { + const el = wrapper.find(`.${AmplifyUI.sectionHeader} > div`).element; + expect(el.textContent.trim()).toEqual(testText); + }); + + it('...should call setUser on mount', () => { + expect(mockSetUser).toHaveBeenCalled(); + }); + + it('...should display setMFA button if !displayTotpSetup', () => { + const el = wrapper.find('#setMfa').exists; + expect(el).toBeTruthy(); + }); + + it('...should not display setMFA button if displayTotpSetup', () => { + wrapper.vm.token = 'token'; + wrapper.vm.displayTotpSetup = true; + const el = wrapper.find('#setMFA').element; + expect(el).toBeFalsy(); + }); + + it('...should call setMFA on setMFA button click', () => { + const el = wrapper.find( + `.${AmplifyUI.sectionFooterPrimaryContent} > button` + ); + el.trigger('click'); + expect(mockSetMFA).toHaveBeenCalled(); + }); + + it('...should display verifyTotpToken button if displayTotpSetup', () => { + wrapper.vm.token = 'token'; + wrapper.vm.displayTotpSetup = true; + const el = wrapper.find('#verify').exists; + expect(el).toBeTruthy(); + }); + + it('...should not display verifyTotpToken button if !displayTotpSetup', () => { + const el = wrapper.find('#verify').element; + expect(el).toBeFalsy(); + }); + + it('...should call verifyTotpToken on verifyTotpToken button click', () => { + wrapper.vm.token = 'token'; + wrapper.vm.displayTotpSetup = true; + const el = wrapper.find('#verify'); + el.trigger('click'); + expect(mockVerifyTotpToken).toHaveBeenCalled(); + }); + + it('...setup should be called when mfaPreference changes', () => { + wrapper.vm.mfaPreference = 'TOTP'; + expect(mockSetup).toHaveBeenCalled(); + }); + + it('...Qrcode element should not exist if displayTotpSetup is false', () => { + const qr = wrapper.find(`.${AmplifyUI.totpQrcode}`).exists(); + expect(qr).toBeFalsy(); + }); + + it('...vQrcode element should exist if displayTotpSetup is true', () => { + wrapper.vm.token = 'testtoken'; + wrapper.vm.displayTotpSetup = true; + const qr = wrapper.find(`.${AmplifyUI.totpQrcode}`).exists(); + expect(qr).toBeTruthy(); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/SignIn.test.js b/packages/aws-amplify-vue/__tests__/SignIn.test.js index 689e81c0046..9df2b61d8bf 100644 --- a/packages/aws-amplify-vue/__tests__/SignIn.test.js +++ b/packages/aws-amplify-vue/__tests__/SignIn.test.js @@ -8,165 +8,168 @@ import AmplifyPlugin from '../src/plugins/AmplifyPlugin'; import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; /* eslint-enable */ - Vue.use(AmplifyPlugin, AmplifyMocks); describe('SignIn', () => { - it('has a mounted hook', () => { - expect(typeof SignIn.mounted).toBe('function'); - }); - - it('sets the correct default data', () => { - expect(typeof SignIn.data).toBe('function'); - const defaultData = SignIn.data(); - expect(defaultData.password).toBe(''); - expect(defaultData.logger).toEqual({}); - expect(defaultData.error).toEqual(''); - }); - - let wrapper; - let header; - let testState; - const mockSignIn = jest.fn(); - const mockForgot = jest.fn(); - const mockSignUp = jest.fn(); - const mockSetError = jest.fn(); - - describe('...when it is mounted without props...', () => { - beforeEach(() => { - wrapper = shallowMount(SignIn); - testState = null; - }); - - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); - - it('...it should be named SignIn', () => { - expect(wrapper.vm.$options.name).toEqual('SignIn'); - }); - - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); - - it('...it should have a signIn method', () => { - expect(wrapper.vm.signIn).toBeTruthy(); - }); - - it('...should have a forgot method', () => { - expect(wrapper.vm.forgot).toBeTruthy(); - }); - - it('...should have a signUp method', () => { - expect(wrapper.vm.signUp).toBeTruthy(); - }); - - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); - - it('...have default options', () => { - expect(wrapper.vm.options.header).toEqual('i18n Sign in to your account'); - expect(wrapper.vm.options.username).toEqual(''); - }); - - it('...have default options', () => { - expect(wrapper.vm.options.header).toEqual('i18n Sign in to your account'); - expect(wrapper.vm.options.username).toEqual(''); - }); - - it('...should call Auth.signIn when signIn function is called', () => { - wrapper.vm.signIn(); - expect(wrapper.vm.$Amplify.Auth.signIn).toHaveBeenCalledTimes(1); - }); - it('...should emit customConfirmSignIn state when signIn function is called and response indicates a custom challenge', async () => { - let customTestState = 0; - AmplifyEventBus.$on('authState', (val) => { - if (val === 'customConfirmSignIn') { - customTestState = 3; - } - }); - await wrapper.vm.signIn(); - expect(customTestState).toEqual(3); - }); - it('...should emit authState when forgot method called', () => { - testState = 0; - AmplifyEventBus.$on('authState', (val) => { - if (val === 'forgotPassword') { - testState = 1; - } - }); - wrapper.vm.forgot(); - expect(testState).toEqual(1); - }); - it('...should emit authState when signUp method called', () => { - testState = 0; - AmplifyEventBus.$on('authState', (val) => { - if (val === 'signUp') { - testState = 2; - } - }); - wrapper.vm.signUp(); - expect(testState).toEqual(2); - }); - }); - - describe('...when it is mounted with props...', () => { - beforeEach(() => { - header = 'TestHeader'; - wrapper = shallowMount(SignIn, { - methods: { - signIn: mockSignIn, - forgot: mockForgot, - signUp: mockSignUp, - setError: mockSetError, - }, - propsData: { - signInConfig: { - username: 'TestPerson', - header, - }, - }, - }); - }); - - afterEach(() => { - mockSignIn.mockReset(); - mockForgot.mockReset(); - mockSignUp.mockReset(); - mockSetError.mockReset(); - }); - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); - - it('...should render the header from props', () => { - const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; - expect(el.textContent).toEqual(header); - }); - - it('...should get the passed username', () => { - expect(wrapper.vm.options.username).toEqual('TestPerson'); - }); - - it('...should call signIn when signIn button is clicked', () => { - const el = wrapper.find(`.${AmplifyUI.sectionFooterPrimaryContent} > button`); - el.trigger('click'); - expect(mockSignIn).toHaveBeenCalled(); - }); - - it('...should not call forgot when reset link is clicked', () => { - const el = wrapper.find(`.${AmplifyUI.hint} > a`); - el.trigger('click'); - expect(mockForgot).toHaveBeenCalled(); - }); - - it('...should call signUp when signUp link is clicked', () => { - const el = wrapper.find(`.${AmplifyUI.sectionFooterSecondaryContent} > a`); - el.trigger('click'); - expect(mockSignUp).toHaveBeenCalled(); - }); - }); + it('has a mounted hook', () => { + expect(typeof SignIn.mounted).toBe('function'); + }); + + it('sets the correct default data', () => { + expect(typeof SignIn.data).toBe('function'); + const defaultData = SignIn.data(); + expect(defaultData.password).toBe(''); + expect(defaultData.logger).toEqual({}); + expect(defaultData.error).toEqual(''); + }); + + let wrapper; + let header; + let testState; + const mockSignIn = jest.fn(); + const mockForgot = jest.fn(); + const mockSignUp = jest.fn(); + const mockSetError = jest.fn(); + + describe('...when it is mounted without props...', () => { + beforeEach(() => { + wrapper = shallowMount(SignIn); + testState = null; + }); + + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); + + it('...it should be named SignIn', () => { + expect(wrapper.vm.$options.name).toEqual('SignIn'); + }); + + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); + + it('...it should have a signIn method', () => { + expect(wrapper.vm.signIn).toBeTruthy(); + }); + + it('...should have a forgot method', () => { + expect(wrapper.vm.forgot).toBeTruthy(); + }); + + it('...should have a signUp method', () => { + expect(wrapper.vm.signUp).toBeTruthy(); + }); + + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); + + it('...have default options', () => { + expect(wrapper.vm.options.header).toEqual('i18n Sign in to your account'); + expect(wrapper.vm.options.username).toEqual(''); + }); + + it('...have default options', () => { + expect(wrapper.vm.options.header).toEqual('i18n Sign in to your account'); + expect(wrapper.vm.options.username).toEqual(''); + }); + + it('...should call Auth.signIn when signIn function is called', () => { + wrapper.vm.signIn(); + expect(wrapper.vm.$Amplify.Auth.signIn).toHaveBeenCalledTimes(1); + }); + it('...should emit customConfirmSignIn state when signIn function is called and response indicates a custom challenge', async () => { + let customTestState = 0; + AmplifyEventBus.$on('authState', val => { + if (val === 'customConfirmSignIn') { + customTestState = 3; + } + }); + await wrapper.vm.signIn(); + expect(customTestState).toEqual(3); + }); + it('...should emit authState when forgot method called', () => { + testState = 0; + AmplifyEventBus.$on('authState', val => { + if (val === 'forgotPassword') { + testState = 1; + } + }); + wrapper.vm.forgot(); + expect(testState).toEqual(1); + }); + it('...should emit authState when signUp method called', () => { + testState = 0; + AmplifyEventBus.$on('authState', val => { + if (val === 'signUp') { + testState = 2; + } + }); + wrapper.vm.signUp(); + expect(testState).toEqual(2); + }); + }); + + describe('...when it is mounted with props...', () => { + beforeEach(() => { + header = 'TestHeader'; + wrapper = shallowMount(SignIn, { + methods: { + signIn: mockSignIn, + forgot: mockForgot, + signUp: mockSignUp, + setError: mockSetError, + }, + propsData: { + signInConfig: { + username: 'TestPerson', + header, + }, + }, + }); + }); + + afterEach(() => { + mockSignIn.mockReset(); + mockForgot.mockReset(); + mockSignUp.mockReset(); + mockSetError.mockReset(); + }); + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); + + it('...should render the header from props', () => { + const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; + expect(el.textContent).toEqual(header); + }); + + it('...should get the passed username', () => { + expect(wrapper.vm.options.username).toEqual('TestPerson'); + }); + + it('...should call signIn when signIn button is clicked', () => { + const el = wrapper.find( + `.${AmplifyUI.sectionFooterPrimaryContent} > button` + ); + el.trigger('click'); + expect(mockSignIn).toHaveBeenCalled(); + }); + + it('...should not call forgot when reset link is clicked', () => { + const el = wrapper.find(`.${AmplifyUI.hint} > a`); + el.trigger('click'); + expect(mockForgot).toHaveBeenCalled(); + }); + + it('...should call signUp when signUp link is clicked', () => { + const el = wrapper.find( + `.${AmplifyUI.sectionFooterSecondaryContent} > a` + ); + el.trigger('click'); + expect(mockSignUp).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/SignOut.test.js b/packages/aws-amplify-vue/__tests__/SignOut.test.js index 14f5cb828ad..9adf3cf14cc 100644 --- a/packages/aws-amplify-vue/__tests__/SignOut.test.js +++ b/packages/aws-amplify-vue/__tests__/SignOut.test.js @@ -10,104 +10,104 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('SignOut', () => { - it('has a mounted hook', () => { - expect(typeof SignOut.mounted).toBe('function'); - }); - - it('sets the correct default data', () => { - expect(typeof SignOut.data).toBe('function'); - const defaultData = SignOut.data(); - expect(defaultData.show).toBe(false); - expect(defaultData.logger).toEqual({}); - expect(defaultData.error).toEqual(''); - }); - - let wrapper; - let msg; - let signOutButton; - const mockSignOut = jest.fn(); - const mockSetError = jest.fn(); - - describe('...when it is mounted without props...', () => { - beforeEach(() => { - wrapper = shallowMount(SignOut); - }); - - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); - - it('...it should be named SignOut', () => { - expect(wrapper.vm.$options.name).toEqual('SignOut'); - }); - - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); - - it('...it should have a signOut method', () => { - expect(wrapper.vm.signOut).toBeTruthy(); - }); - - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); - - it('...have default options', () => { - expect(wrapper.vm.options.msg).toEqual(null); - expect(wrapper.vm.options.signOutButton).toEqual('i18n Sign Out'); - }); - }); - - describe('...when the methods are not mocked...', () => { - wrapper = mount(SignOut); - it('...should have a signOut method that calls Amplify.Auth.SignOut', () => { - wrapper.vm.signOut(); - expect(wrapper.vm.$Amplify.Auth.signOut).toHaveBeenCalled(); - }); - }); - - describe('...when it is mounted with props...', () => { - beforeEach(() => { - msg = 'Hello User'; - signOutButton = 'Get Outta Here'; - wrapper = shallowMount(SignOut, { - methods: { - signOut: mockSignOut, - setError: mockSetError, - }, - propsData: { - signOutConfig: { - msg, - signOutButton, - }, - }, - }); - }); - - afterEach(() => { - mockSignOut.mockReset(); - mockSetError.mockReset(); - }); - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); - - it('...should render the msg from props', () => { - const el = wrapper.find(`.${AmplifyUI.inputLabel}`).element; - expect(el.textContent).toEqual(msg); - }); - - it('...should get the passed signOut button text', () => { - const text = wrapper.find('button').text(); - expect(text).toEqual(signOutButton); - }); - - it('...should call SignOut when SignOut button is clicked', () => { - const el = wrapper.find('button'); - el.trigger('click'); - expect(mockSignOut).toHaveBeenCalled(); - }); - }); + it('has a mounted hook', () => { + expect(typeof SignOut.mounted).toBe('function'); + }); + + it('sets the correct default data', () => { + expect(typeof SignOut.data).toBe('function'); + const defaultData = SignOut.data(); + expect(defaultData.show).toBe(false); + expect(defaultData.logger).toEqual({}); + expect(defaultData.error).toEqual(''); + }); + + let wrapper; + let msg; + let signOutButton; + const mockSignOut = jest.fn(); + const mockSetError = jest.fn(); + + describe('...when it is mounted without props...', () => { + beforeEach(() => { + wrapper = shallowMount(SignOut); + }); + + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); + + it('...it should be named SignOut', () => { + expect(wrapper.vm.$options.name).toEqual('SignOut'); + }); + + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); + + it('...it should have a signOut method', () => { + expect(wrapper.vm.signOut).toBeTruthy(); + }); + + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); + + it('...have default options', () => { + expect(wrapper.vm.options.msg).toEqual(null); + expect(wrapper.vm.options.signOutButton).toEqual('i18n Sign Out'); + }); + }); + + describe('...when the methods are not mocked...', () => { + wrapper = mount(SignOut); + it('...should have a signOut method that calls Amplify.Auth.SignOut', () => { + wrapper.vm.signOut(); + expect(wrapper.vm.$Amplify.Auth.signOut).toHaveBeenCalled(); + }); + }); + + describe('...when it is mounted with props...', () => { + beforeEach(() => { + msg = 'Hello User'; + signOutButton = 'Get Outta Here'; + wrapper = shallowMount(SignOut, { + methods: { + signOut: mockSignOut, + setError: mockSetError, + }, + propsData: { + signOutConfig: { + msg, + signOutButton, + }, + }, + }); + }); + + afterEach(() => { + mockSignOut.mockReset(); + mockSetError.mockReset(); + }); + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); + + it('...should render the msg from props', () => { + const el = wrapper.find(`.${AmplifyUI.inputLabel}`).element; + expect(el.textContent).toEqual(msg); + }); + + it('...should get the passed signOut button text', () => { + const text = wrapper.find('button').text(); + expect(text).toEqual(signOutButton); + }); + + it('...should call SignOut when SignOut button is clicked', () => { + const el = wrapper.find('button'); + el.trigger('click'); + expect(mockSignOut).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/SignUp.test.js b/packages/aws-amplify-vue/__tests__/SignUp.test.js index e56a53b24c9..60795f00bec 100644 --- a/packages/aws-amplify-vue/__tests__/SignUp.test.js +++ b/packages/aws-amplify-vue/__tests__/SignUp.test.js @@ -6,277 +6,286 @@ import SignUp from '../src/components/authenticator/SignUp.vue'; import PhoneField from '../src/components/authenticator/PhoneField.vue'; import AmplifyPlugin from '../src/plugins/AmplifyPlugin'; import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; -import signUpWithUsername, { signUpWithEmailFields, signUpWithPhoneNumberFields } from '../src/assets/default-sign-up-fields'; +import signUpWithUsername, { + signUpWithEmailFields, + signUpWithPhoneNumberFields, +} from '../src/assets/default-sign-up-fields'; /* eslint-enable */ Vue.use(AmplifyPlugin, AmplifyMocks); describe('SignUp', () => { - it('has a mounted hook', () => { - expect(typeof SignUp.mounted).toBe('function'); - }); + it('has a mounted hook', () => { + expect(typeof SignUp.mounted).toBe('function'); + }); - it('sets the correct default data', () => { - expect(typeof SignUp.data).toBe('function'); - const defaultData = SignUp.data(); - expect(defaultData.logger).toEqual({}); - expect(defaultData.error).toEqual(''); - expect(defaultData.phoneNumber).toEqual(''); - expect(defaultData.defaultSignUpFields).toEqual(signUpWithUsername); - }); + it('sets the correct default data', () => { + expect(typeof SignUp.data).toBe('function'); + const defaultData = SignUp.data(); + expect(defaultData.logger).toEqual({}); + expect(defaultData.error).toEqual(''); + expect(defaultData.phoneNumber).toEqual(''); + expect(defaultData.defaultSignUpFields).toEqual(signUpWithUsername); + }); - let wrapper; - let header; - const mockSignUp = jest.fn(); - const mockValidate = jest.fn(); - const mockSignIn = jest.fn(); - const mockClear = jest.fn(); - const mockSetError = jest.fn(); + let wrapper; + let header; + const mockSignUp = jest.fn(); + const mockValidate = jest.fn(); + const mockSignIn = jest.fn(); + const mockClear = jest.fn(); + const mockSetError = jest.fn(); - describe('...when it is mounted without props...', () => { - beforeEach(() => { - wrapper = shallowMount(SignUp); - }); + describe('...when it is mounted without props...', () => { + beforeEach(() => { + wrapper = shallowMount(SignUp); + }); - it('...it should use the amplify plugin with passed modules', () => { - expect(wrapper.vm.$Amplify).toBeTruthy(); - }); + it('...it should use the amplify plugin with passed modules', () => { + expect(wrapper.vm.$Amplify).toBeTruthy(); + }); - it('...it should be named SignUp', () => { - expect(wrapper.vm.$options.name).toEqual('SignUp'); - }); + it('...it should be named SignUp', () => { + expect(wrapper.vm.$options.name).toEqual('SignUp'); + }); - it('...it should instantiate a logger with the name of the component', () => { - expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); - }); + it('...it should instantiate a logger with the name of the component', () => { + expect(wrapper.vm.logger.name).toEqual(wrapper.vm.$options.name); + }); - it('...it should have a signIn method', () => { - expect(wrapper.vm.signIn).toBeTruthy(); - }); + it('...it should have a signIn method', () => { + expect(wrapper.vm.signIn).toBeTruthy(); + }); - it('...should have a validate method', () => { - expect(wrapper.vm.validate).toBeTruthy(); - }); + it('...should have a validate method', () => { + expect(wrapper.vm.validate).toBeTruthy(); + }); - it('...should have a signUp method', () => { - expect(wrapper.vm.signUp).toBeTruthy(); - }); + it('...should have a signUp method', () => { + expect(wrapper.vm.signUp).toBeTruthy(); + }); - it('...should have a clear method', () => { - expect(wrapper.vm.clear).toBeTruthy(); - }); + it('...should have a clear method', () => { + expect(wrapper.vm.clear).toBeTruthy(); + }); - it('...it should have a setError method', () => { - expect(wrapper.vm.setError).toBeTruthy(); - }); + it('...it should have a setError method', () => { + expect(wrapper.vm.setError).toBeTruthy(); + }); - it('...shoud render a phone field component', () => { - const phoneField = wrapper.find(PhoneField); - expect(phoneField).toBeTruthy(); - expect(phoneField.props()).toEqual({ - "defaultCountryCode": undefined, - "invalid": undefined, - "placeholder": "Phone Number", - "required": true - }); - }); + it('...shoud render a phone field component', () => { + const phoneField = wrapper.find(PhoneField); + expect(phoneField).toBeTruthy(); + expect(phoneField.props()).toEqual({ + defaultCountryCode: undefined, + invalid: undefined, + placeholder: 'Phone Number', + required: true, + }); + }); - it('...have default options', () => { - expect(wrapper.vm.options.header).toEqual('i18n Create a new account'); - expect(wrapper.vm.options.signUpFields).toEqual([ - { - label: 'Username', - key: 'username', - required: true, - placeholder: 'Username', - displayOrder: 1, - }, - { - label: 'Password', - key: 'password', - required: true, - placeholder: 'Password', - type: 'password', - displayOrder: 2, - }, - { - label: 'Email', - key: 'email', - required: true, - placeholder: 'Email', - type: 'email', - displayOrder: 3 - }, - { - label: 'Phone Number', - key: 'phone_number', - placeholder: 'Phone Number', - required: true, - displayOrder: 4 - }, - ]); - }); + it('...have default options', () => { + expect(wrapper.vm.options.header).toEqual('i18n Create a new account'); + expect(wrapper.vm.options.signUpFields).toEqual([ + { + label: 'Username', + key: 'username', + required: true, + placeholder: 'Username', + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + placeholder: 'Password', + type: 'password', + displayOrder: 2, + }, + { + label: 'Email', + key: 'email', + required: true, + placeholder: 'Email', + type: 'email', + displayOrder: 3, + }, + { + label: 'Phone Number', + key: 'phone_number', + placeholder: 'Phone Number', + required: true, + displayOrder: 4, + }, + ]); + }); - it('...it should not call Auth.signUp when signUp method is called and fields are empty', () => { // eslint-disable-line - wrapper.vm.signUp(); - expect(wrapper.vm.$Amplify.Auth.signUp).not.toBeCalled(); - }); + it('...it should not call Auth.signUp when signUp method is called and fields are empty', () => { + // eslint-disable-line + wrapper.vm.signUp(); + expect(wrapper.vm.$Amplify.Auth.signUp).not.toBeCalled(); + }); - it('...it should call Auth.signUp when signUp method is called and fields are populated', () => { // eslint-disable-line - wrapper.vm.options.signUpFields.forEach((el) => { - el.value = 'iampopulated'; - }); - wrapper.vm.signUp(); - expect(wrapper.vm.$Amplify.Auth.signUp).toBeCalled(); - }); - }); + it('...it should call Auth.signUp when signUp method is called and fields are populated', () => { + // eslint-disable-line + wrapper.vm.options.signUpFields.forEach(el => { + el.value = 'iampopulated'; + }); + wrapper.vm.signUp(); + expect(wrapper.vm.$Amplify.Auth.signUp).toBeCalled(); + }); + }); - describe('...when it is mounted with props...', () => { - let signUpFields = []; - beforeEach(() => { - header = 'TestHeader'; - wrapper = shallowMount(SignUp, { - methods: { - signIn: mockSignIn, - validate: mockValidate, - signUp: mockSignUp, - setError: mockSetError, - clear: mockClear, - }, - propsData: { - signUpConfig: { - header, - signUpFields, - }, - }, - }); - }); + describe('...when it is mounted with props...', () => { + let signUpFields = []; + beforeEach(() => { + header = 'TestHeader'; + wrapper = shallowMount(SignUp, { + methods: { + signIn: mockSignIn, + validate: mockValidate, + signUp: mockSignUp, + setError: mockSetError, + clear: mockClear, + }, + propsData: { + signUpConfig: { + header, + signUpFields, + }, + }, + }); + }); - afterEach(() => { - mockSignUp.mockReset(); - mockValidate.mockReset(); - mockSignIn.mockReset(); - mockClear.mockReset(); - mockSetError.mockReset(); - }); - it('...should not set the error property', () => { - expect(wrapper.vm.error).toEqual(''); - expect(mockSetError).not.toHaveBeenCalled(); - }); + afterEach(() => { + mockSignUp.mockReset(); + mockValidate.mockReset(); + mockSignIn.mockReset(); + mockClear.mockReset(); + mockSetError.mockReset(); + }); + it('...should not set the error property', () => { + expect(wrapper.vm.error).toEqual(''); + expect(mockSetError).not.toHaveBeenCalled(); + }); - it('...should render the header from props', () => { - const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; - expect(el.textContent).toEqual(header); - }); + it('...should render the header from props', () => { + const el = wrapper.find(`.${AmplifyUI.sectionHeader}`).element; + expect(el.textContent).toEqual(header); + }); - it('...should call signIn when signIn button is clicked', () => { - const el = wrapper.find(`.${AmplifyUI.sectionFooterPrimaryContent} > button`); - el.trigger('click'); - expect(mockSignUp).toHaveBeenCalled(); - }); - }); + it('...should call signIn when signIn button is clicked', () => { + const el = wrapper.find( + `.${AmplifyUI.sectionFooterPrimaryContent} > button` + ); + el.trigger('click'); + expect(mockSignUp).toHaveBeenCalled(); + }); + }); - describe('...when signUpFields are passed...', () => { - const signUpFields = [ - { - label: 'Address', - key: 'address', - required: true, - type: 'string', - }, - { - label: 'Test Email', - key: 'email', - required: true, - type: 'string', - }, - ]; - beforeEach(() => { - header = 'TestHeader'; - wrapper = shallowMount(SignUp, { - methods: { - signIn: mockSignIn, - validate: mockValidate, - signUp: mockSignUp, - setError: mockSetError, - clear: mockClear, - }, - propsData: { - signUpConfig: { - header, - signUpFields, - }, - }, - }); - }); + describe('...when signUpFields are passed...', () => { + const signUpFields = [ + { + label: 'Address', + key: 'address', + required: true, + type: 'string', + }, + { + label: 'Test Email', + key: 'email', + required: true, + type: 'string', + }, + ]; + beforeEach(() => { + header = 'TestHeader'; + wrapper = shallowMount(SignUp, { + methods: { + signIn: mockSignIn, + validate: mockValidate, + signUp: mockSignUp, + setError: mockSetError, + clear: mockClear, + }, + propsData: { + signUpConfig: { + header, + signUpFields, + }, + }, + }); + }); - afterEach(() => { - mockSignUp.mockReset(); - mockValidate.mockReset(); - mockSignIn.mockReset(); - mockClear.mockReset(); - mockSetError.mockReset(); - }); + afterEach(() => { + mockSignUp.mockReset(); + mockValidate.mockReset(); + mockSignIn.mockReset(); + mockClear.mockReset(); + mockSetError.mockReset(); + }); - it('...should accept new signUpFields an add them to the default Array', () => { - expect(wrapper.vm.options.signUpFields.length).toEqual(5); - }); + it('...should accept new signUpFields an add them to the default Array', () => { + expect(wrapper.vm.options.signUpFields.length).toEqual(5); + }); - it('...should overwrite existing fields from default array', () => { - const email = wrapper.vm.options.signUpFields.find(x => x.key === 'email'); - expect(email.label).toEqual('Test Email'); - }); - }); - describe('...when phone number field is customized...', () => { - const signUpFields = [ - { - label: 'My Phone Number Field', - key: 'phone_number', - required: false, - type: 'string', - placeholder: 'the placeholder' - } - ]; - beforeEach(() => { - wrapper = shallowMount(SignUp, { - methods: { - signIn: mockSignIn, - validate: mockValidate, - signUp: mockSignUp, - setError: mockSetError, - clear: mockClear, - }, - propsData: { - signUpConfig: { - defaultCountryCode: '86', - hiddenDefaults: ['phone_number'], - signUpFields, - }, - }, - }); - }); + it('...should overwrite existing fields from default array', () => { + const email = wrapper.vm.options.signUpFields.find( + x => x.key === 'email' + ); + expect(email.label).toEqual('Test Email'); + }); + }); + describe('...when phone number field is customized...', () => { + const signUpFields = [ + { + label: 'My Phone Number Field', + key: 'phone_number', + required: false, + type: 'string', + placeholder: 'the placeholder', + }, + ]; + beforeEach(() => { + wrapper = shallowMount(SignUp, { + methods: { + signIn: mockSignIn, + validate: mockValidate, + signUp: mockSignUp, + setError: mockSetError, + clear: mockClear, + }, + propsData: { + signUpConfig: { + defaultCountryCode: '86', + hiddenDefaults: ['phone_number'], + signUpFields, + }, + }, + }); + }); - afterEach(() => { - mockSignUp.mockReset(); - mockValidate.mockReset(); - mockSignIn.mockReset(); - mockClear.mockReset(); - mockSetError.mockReset(); - }); + afterEach(() => { + mockSignUp.mockReset(); + mockValidate.mockReset(); + mockSignIn.mockReset(); + mockClear.mockReset(); + mockSetError.mockReset(); + }); - it('...should accept new signUpFields an add them to the default Array', () => { - expect(wrapper.vm.options.signUpFields.length).toEqual(4); - }); + it('...should accept new signUpFields an add them to the default Array', () => { + expect(wrapper.vm.options.signUpFields.length).toEqual(4); + }); - it('...shoud pass props to phone field', () => { - const phoneField = wrapper.find(PhoneField); - expect(phoneField).toBeTruthy(); - expect(phoneField.props()).toEqual({ - "defaultCountryCode": "86", - "invalid": undefined, - "placeholder": "the placeholder", - "required": false - }); - }); - }); + it('...shoud pass props to phone field', () => { + const phoneField = wrapper.find(PhoneField); + expect(phoneField).toBeTruthy(); + expect(phoneField.props()).toEqual({ + defaultCountryCode: '86', + invalid: undefined, + placeholder: 'the placeholder', + required: false, + }); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/SumerianScene.test.js b/packages/aws-amplify-vue/__tests__/SumerianScene.test.js index a894d4cff4b..2b051917ce9 100644 --- a/packages/aws-amplify-vue/__tests__/SumerianScene.test.js +++ b/packages/aws-amplify-vue/__tests__/SumerianScene.test.js @@ -9,49 +9,49 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('SumerianScene', () => { - let wrapper; - - describe('mounted with props but methods not mocked...', () => { - beforeEach(() => { - global.open = jest.fn(); - wrapper = shallowMount(SumerianScene, { - propsData: { - sceneName: 'testSceneName', - }, - }); - }); - - it('...it should be named SumerianScene', () => { - expect(wrapper.vm.$options.name).toEqual('SumerianScene'); - }); - - it('...should call scene setup functions after scene load', async () => { - await wrapper.vm.loadAndStartScene(); - expect(wrapper.vm.$Amplify.XR.onSceneEvent).toHaveBeenCalled(); - expect(wrapper.vm.$Amplify.XR.isVRCapable).toHaveBeenCalled(); - expect(wrapper.vm.$Amplify.XR.isMuted).toHaveBeenCalled(); - expect(wrapper.vm.$Amplify.XR.start).toHaveBeenCalled(); - expect(wrapper.vm.$Amplify.XR.loadScene).toHaveBeenCalled(); - }); - - it('...should call $Amplify.XR.setMuted after setMuted is called', () => { - expect(wrapper.vm.$Amplify.XR.setMuted).not.toHaveBeenCalled(); - wrapper.vm.setMuted(true); - expect(wrapper.vm.$Amplify.XR.setMuted).toHaveBeenCalled(); - }); - - it('...should call toggle isVRPresentationActive after toggleVRPresentation is called', () => { - expect(wrapper.vm.isVRPresentationActive).toBeFalsy(); - wrapper.vm.toggleVRPresentation(); - expect(wrapper.vm.$Amplify.XR.enterVR).toHaveBeenCalled(); - expect(wrapper.vm.isVRPresentationActive).toBeTruthy(); - - wrapper.vm.toggleVRPresentation(); - expect(wrapper.vm.$Amplify.XR.exitVR).toHaveBeenCalled(); - }); - - it('...should have sceneName prop', () => { - expect(wrapper.vm.sceneName).toEqual('testSceneName'); - }); - }); + let wrapper; + + describe('mounted with props but methods not mocked...', () => { + beforeEach(() => { + global.open = jest.fn(); + wrapper = shallowMount(SumerianScene, { + propsData: { + sceneName: 'testSceneName', + }, + }); + }); + + it('...it should be named SumerianScene', () => { + expect(wrapper.vm.$options.name).toEqual('SumerianScene'); + }); + + it('...should call scene setup functions after scene load', async () => { + await wrapper.vm.loadAndStartScene(); + expect(wrapper.vm.$Amplify.XR.onSceneEvent).toHaveBeenCalled(); + expect(wrapper.vm.$Amplify.XR.isVRCapable).toHaveBeenCalled(); + expect(wrapper.vm.$Amplify.XR.isMuted).toHaveBeenCalled(); + expect(wrapper.vm.$Amplify.XR.start).toHaveBeenCalled(); + expect(wrapper.vm.$Amplify.XR.loadScene).toHaveBeenCalled(); + }); + + it('...should call $Amplify.XR.setMuted after setMuted is called', () => { + expect(wrapper.vm.$Amplify.XR.setMuted).not.toHaveBeenCalled(); + wrapper.vm.setMuted(true); + expect(wrapper.vm.$Amplify.XR.setMuted).toHaveBeenCalled(); + }); + + it('...should call toggle isVRPresentationActive after toggleVRPresentation is called', () => { + expect(wrapper.vm.isVRPresentationActive).toBeFalsy(); + wrapper.vm.toggleVRPresentation(); + expect(wrapper.vm.$Amplify.XR.enterVR).toHaveBeenCalled(); + expect(wrapper.vm.isVRPresentationActive).toBeTruthy(); + + wrapper.vm.toggleVRPresentation(); + expect(wrapper.vm.$Amplify.XR.exitVR).toHaveBeenCalled(); + }); + + it('...should have sceneName prop', () => { + expect(wrapper.vm.sceneName).toEqual('testSceneName'); + }); + }); }); diff --git a/packages/aws-amplify-vue/__tests__/UsernameField.test.js b/packages/aws-amplify-vue/__tests__/UsernameField.test.js index 692fa104248..08498915f1d 100644 --- a/packages/aws-amplify-vue/__tests__/UsernameField.test.js +++ b/packages/aws-amplify-vue/__tests__/UsernameField.test.js @@ -10,108 +10,117 @@ import * as AmplifyMocks from '../__mocks__/Amplify.mocks'; Vue.use(AmplifyPlugin, AmplifyMocks); describe('UsernameField', () => { - it('sets the correct default data', () => { - expect(typeof UsernameField.data).toBe('function'); - const defaultData = UsernameField.data(); - expect(defaultData.username).toEqual(''); - expect(defaultData.email).toEqual(''); - expect(defaultData.phoneNumberRequired).toEqual(true); - }); + it('sets the correct default data', () => { + expect(typeof UsernameField.data).toBe('function'); + const defaultData = UsernameField.data(); + expect(defaultData.username).toEqual(''); + expect(defaultData.email).toEqual(''); + expect(defaultData.phoneNumberRequired).toEqual(true); + }); - let wrapper = null; - const mockEmailChanged = jest.fn(); - const mockUsernameChanged = jest.fn(); - const mockPhoneNumberChanged = jest.fn(); + let wrapper = null; + const mockEmailChanged = jest.fn(); + const mockUsernameChanged = jest.fn(); + const mockPhoneNumberChanged = jest.fn(); - describe('when usernameAttributes is email', () => { - beforeEach(() => { - wrapper = shallowMount(UsernameField, { - methods: { - phoneNumberChanged: mockPhoneNumberChanged, - usernameChanged: mockUsernameChanged, - emailChanged: mockEmailChanged - }, - propsData: { - usernameAttributes: 'email' - } - }); - }); + describe('when usernameAttributes is email', () => { + beforeEach(() => { + wrapper = shallowMount(UsernameField, { + methods: { + phoneNumberChanged: mockPhoneNumberChanged, + usernameChanged: mockUsernameChanged, + emailChanged: mockEmailChanged, + }, + propsData: { + usernameAttributes: 'email', + }, + }); + }); - afterEach(() => { - mockPhoneNumberChanged.mockReset(); - mockEmailChanged.mockReset(); - mockUsernameChanged.mockReset(); - }); + afterEach(() => { + mockPhoneNumberChanged.mockReset(); + mockEmailChanged.mockReset(); + mockUsernameChanged.mockReset(); + }); - it('only render email input', () => { - expect(wrapper.findAll('input').length).toBe(1); - expect(wrapper.findAll(PhoneField).length).toBe(0); - }); + it('only render email input', () => { + expect(wrapper.findAll('input').length).toBe(1); + expect(wrapper.findAll(PhoneField).length).toBe(0); + }); - it('trigger emailChanged when input is filled', () => { - wrapper.findAll('input').at(0).trigger('keyup'); - expect(mockEmailChanged).toBeCalled(); - }); - }); + it('trigger emailChanged when input is filled', () => { + wrapper + .findAll('input') + .at(0) + .trigger('keyup'); + expect(mockEmailChanged).toBeCalled(); + }); + }); - describe('when usernameAttributes is not defined', () => { - beforeEach(() => { - wrapper = shallowMount(UsernameField, { - methods: { - phoneNumberChanged: mockPhoneNumberChanged, - usernameChanged: mockUsernameChanged, - emailChanged: mockEmailChanged - }, - propsData: { - usernameAttributes: undefined - } - }); - }); + describe('when usernameAttributes is not defined', () => { + beforeEach(() => { + wrapper = shallowMount(UsernameField, { + methods: { + phoneNumberChanged: mockPhoneNumberChanged, + usernameChanged: mockUsernameChanged, + emailChanged: mockEmailChanged, + }, + propsData: { + usernameAttributes: undefined, + }, + }); + }); - afterEach(() => { - mockPhoneNumberChanged.mockReset(); - mockEmailChanged.mockReset(); - mockUsernameChanged.mockReset(); - }); + afterEach(() => { + mockPhoneNumberChanged.mockReset(); + mockEmailChanged.mockReset(); + mockUsernameChanged.mockReset(); + }); - it('only render email input', () => { - expect(wrapper.findAll('input').length).toBe(1); - expect(wrapper.findAll(PhoneField).length).toBe(0); - }); + it('only render email input', () => { + expect(wrapper.findAll('input').length).toBe(1); + expect(wrapper.findAll(PhoneField).length).toBe(0); + }); - it('trigger emailChanged when input is filled', () => { - wrapper.findAll('input').at(0).trigger('keyup'); - expect(mockUsernameChanged).toBeCalled(); - }); - }); + it('trigger emailChanged when input is filled', () => { + wrapper + .findAll('input') + .at(0) + .trigger('keyup'); + expect(mockUsernameChanged).toBeCalled(); + }); + }); - describe('when usernameAttributes is phone_number', () => { - beforeEach(() => { - wrapper = shallowMount(UsernameField, { - methods: { - phoneNumberChanged: mockPhoneNumberChanged, - usernameChanged: mockUsernameChanged, - emailChanged: mockEmailChanged - }, - propsData: { - usernameAttributes: 'phone_number' - } - }); - }); + describe('when usernameAttributes is phone_number', () => { + beforeEach(() => { + wrapper = shallowMount(UsernameField, { + methods: { + phoneNumberChanged: mockPhoneNumberChanged, + usernameChanged: mockUsernameChanged, + emailChanged: mockEmailChanged, + }, + propsData: { + usernameAttributes: 'phone_number', + }, + }); + }); - afterEach(() => { - mockPhoneNumberChanged.mockReset(); - mockEmailChanged.mockReset(); - mockUsernameChanged.mockReset(); - }); + afterEach(() => { + mockPhoneNumberChanged.mockReset(); + mockEmailChanged.mockReset(); + mockUsernameChanged.mockReset(); + }); - it('only render email input', () => { - expect(wrapper.findAll(PhoneField).length).toBe(1); - }); + it('only render email input', () => { + expect(wrapper.findAll(PhoneField).length).toBe(1); + }); - it('trigger emailChanged when input is filled', () => { - wrapper.findAll(PhoneField).at(0).vm.$emit('phone-number-changed'); - expect(mockPhoneNumberChanged).toBeCalled(); - }); - }); -}); \ No newline at end of file + it('trigger emailChanged when input is filled', () => { + wrapper + .findAll(PhoneField) + .at(0) + .vm.$emit('phone-number-changed'); + expect(mockPhoneNumberChanged).toBeCalled(); + }); + }); +}); diff --git a/packages/aws-amplify-vue/babel.config.js b/packages/aws-amplify-vue/babel.config.js index 91be2448dd9..a7722b54b66 100644 --- a/packages/aws-amplify-vue/babel.config.js +++ b/packages/aws-amplify-vue/babel.config.js @@ -1,5 +1,3 @@ module.exports = { - presets: [ - '@vue/app', - ], + presets: ['@vue/app'], }; diff --git a/packages/aws-amplify-vue/jest.config.js b/packages/aws-amplify-vue/jest.config.js index 613133ceea3..780e0138c9c 100644 --- a/packages/aws-amplify-vue/jest.config.js +++ b/packages/aws-amplify-vue/jest.config.js @@ -1,26 +1,20 @@ module.exports = { - moduleFileExtensions: [ - 'js', - 'jsx', - 'json', - 'vue', - ], - transform: { - '^.+\\.vue$': 'vue-jest', - '.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub', - '^.+\\.jsx?$': 'babel-jest', - }, - moduleNameMapper: { - '^@/(.*)$': '/src/$1', - }, - snapshotSerializers: [ - 'jest-serializer-vue', - ], - testMatch: [ - '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)', - ], - testURL: 'http://localhost/', - collectCoverage: true, - coverageReporters: ['lcov'], - setupTestFrameworkScriptFile: "/test_setup/setup-jest.ts", + moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], + transform: { + '^.+\\.vue$': 'vue-jest', + '.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': + 'jest-transform-stub', + '^.+\\.jsx?$': 'babel-jest', + }, + moduleNameMapper: { + '^@/(.*)$': '/src/$1', + }, + snapshotSerializers: ['jest-serializer-vue'], + testMatch: [ + '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)', + ], + testURL: 'http://localhost/', + collectCoverage: true, + coverageReporters: ['lcov'], + setupTestFrameworkScriptFile: '/test_setup/setup-jest.ts', }; diff --git a/packages/aws-amplify-vue/src/assets/countries.js b/packages/aws-amplify-vue/src/assets/countries.js index 2039736d19f..f92f1b0cb90 100644 --- a/packages/aws-amplify-vue/src/assets/countries.js +++ b/packages/aws-amplify-vue/src/assets/countries.js @@ -1,220 +1,220 @@ const countries = [ - { countryCode: 'US', value: '1', label: 'USA (+1)' }, - { countryCode: 'GB', value: '44', label: 'UK (+44)' }, - { countryCode: 'DZ', value: '213', label: 'Algeria (+213)' }, - { countryCode: 'AD', value: '376', label: 'Andorra (+376)' }, - { countryCode: 'AO', value: '244', label: 'Angola (+244)' }, - { countryCode: 'AI', value: '1264', label: 'Anguilla (+1264)' }, - { countryCode: 'AG', value: '1268', label: 'Antigua & Barbuda (+1268)' }, - { countryCode: 'AR', value: '54', label: 'Argentina (+54)' }, - { countryCode: 'AM', value: '374', label: 'Armenia (+374)' }, - { countryCode: 'AW', value: '297', label: 'Aruba (+297)' }, - { countryCode: 'AU', value: '61', label: 'Australia (+61)' }, - { countryCode: 'AT', value: '43', label: 'Austria (+43)' }, - { countryCode: 'AZ', value: '994', label: 'Azerbaijan (+994)' }, - { countryCode: 'BS', value: '1242', label: 'Bahamas (+1242)' }, - { countryCode: 'BH', value: '973', label: 'Bahrain (+973)' }, - { countryCode: 'BD', value: '880', label: 'Bangladesh (+880)' }, - { countryCode: 'BB', value: '1246', label: 'Barbados (+1246)' }, - { countryCode: 'BY', value: '375', label: 'Belarus (+375)' }, - { countryCode: 'BE', value: '32', label: 'Belgium (+32)' }, - { countryCode: 'BZ', value: '501', label: 'Belize (+501)' }, - { countryCode: 'BJ', value: '229', label: 'Benin (+229)' }, - { countryCode: 'BM', value: '1441', label: 'Bermuda (+1441)' }, - { countryCode: 'BT', value: '975', label: 'Bhutan (+975)' }, - { countryCode: 'BO', value: '591', label: 'Bolivia (+591)' }, - { countryCode: 'BA', value: '387', label: 'Bosnia Herzegovina (+387)' }, - { countryCode: 'BW', value: '267', label: 'Botswana (+267)' }, - { countryCode: 'BR', value: '55', label: 'Brazil (+55)' }, - { countryCode: 'BN', value: '673', label: 'Brunei (+673)' }, - { countryCode: 'BG', value: '359', label: 'Bulgaria (+359)' }, - { countryCode: 'BF', value: '226', label: 'Burkina Faso (+226)' }, - { countryCode: 'BI', value: '257', label: 'Burundi (+257)' }, - { countryCode: 'KH', value: '855', label: 'Cambodia (+855)' }, - { countryCode: 'CM', value: '237', label: 'Cameroon (+237)' }, - { countryCode: 'CA', value: '1', label: 'Canada (+1)' }, - { countryCode: 'CV', value: '238', label: 'Cape Verde Islands (+238)' }, - { countryCode: 'KY', value: '1345', label: 'Cayman Islands (+1345)' }, - { countryCode: 'CF', value: '236', label: 'Central African Republic (+236)' }, - { countryCode: 'CL', value: '56', label: 'Chile (+56)' }, - { countryCode: 'CN', value: '86', label: 'China (+86)' }, - { countryCode: 'CO', value: '57', label: 'Colombia (+57)' }, - { countryCode: 'KM', value: '269', label: 'Comoros (+269)' }, - { countryCode: 'CG', value: '242', label: 'Congo (+242)' }, - { countryCode: 'CK', value: '682', label: 'Cook Islands (+682)' }, - { countryCode: 'CR', value: '506', label: 'Costa Rica (+506)' }, - { countryCode: 'HR', value: '385', label: 'Croatia (+385)' }, - { countryCode: 'CU', value: '53', label: 'Cuba (+53)' }, - { countryCode: 'CW', value: '599', label: 'Curacao (+599)' }, - { countryCode: 'CY', value: '90392', label: 'Cyprus North (+90392)' }, - { countryCode: 'CY', value: '357', label: 'Cyprus South (+357)' }, - { countryCode: 'CZ', value: '42', label: 'Czech Republic (+42)' }, - { countryCode: 'DK', value: '45', label: 'Denmark (+45)' }, - { countryCode: 'DJ', value: '253', label: 'Djibouti (+253)' }, - { countryCode: 'DM', value: '1809', label: 'Dominica (+1809)' }, - { countryCode: 'DO', value: '1809', label: 'Dominican Republic (+1809)' }, - { countryCode: 'EC', value: '593', label: 'Ecuador (+593)' }, - { countryCode: 'EG', value: '20', label: 'Egypt (+20)' }, - { countryCode: 'SV', value: '503', label: 'El Salvador (+503)' }, - { countryCode: 'GQ', value: '240', label: 'Equatorial Guinea (+240)' }, - { countryCode: 'ER', value: '291', label: 'Eritrea (+291)' }, - { countryCode: 'EE', value: '372', label: 'Estonia (+372)' }, - { countryCode: 'ET', value: '251', label: 'Ethiopia (+251)' }, - { countryCode: 'FK', value: '500', label: 'Falkland Islands (+500)' }, - { countryCode: 'FO', value: '298', label: 'Faroe Islands (+298)' }, - { countryCode: 'FJ', value: '679', label: 'Fiji (+679)' }, - { countryCode: 'FI', value: '358', label: 'Finland (+358)' }, - { countryCode: 'FR', value: '33', label: 'France (+33)' }, - { countryCode: 'GF', value: '594', label: 'French Guiana (+594)' }, - { countryCode: 'PF', value: '689', label: 'French Polynesia (+689)' }, - { countryCode: 'GA', value: '241', label: 'Gabon (+241)' }, - { countryCode: 'GM', value: '220', label: 'Gambia (+220)' }, - { countryCode: 'GE', value: '7880', label: 'Georgia (+7880)' }, - { countryCode: 'DE', value: '49', label: 'Germany (+49)' }, - { countryCode: 'GH', value: '233', label: 'Ghana (+233)' }, - { countryCode: 'GI', value: '350', label: 'Gibraltar (+350)' }, - { countryCode: 'GR', value: '30', label: 'Greece (+30)' }, - { countryCode: 'GL', value: '299', label: 'Greenland (+299)' }, - { countryCode: 'GD', value: '1473', label: 'Grenada (+1473)' }, - { countryCode: 'GP', value: '590', label: 'Guadeloupe (+590)' }, - { countryCode: 'GU', value: '671', label: 'Guam (+671)' }, - { countryCode: 'GT', value: '502', label: 'Guatemala (+502)' }, - { countryCode: 'GN', value: '224', label: 'Guinea (+224)' }, - { countryCode: 'GW', value: '245', label: 'Guinea - Bissau (+245)' }, - { countryCode: 'GY', value: '592', label: 'Guyana (+592)' }, - { countryCode: 'HT', value: '509', label: 'Haiti (+509)' }, - { countryCode: 'HN', value: '504', label: 'Honduras (+504)' }, - { countryCode: 'HK', value: '852', label: 'Hong Kong (+852)' }, - { countryCode: 'HU', value: '36', label: 'Hungary (+36)' }, - { countryCode: 'IS', value: '354', label: 'Iceland (+354)' }, - { countryCode: 'IN', value: '91', label: 'India (+91)' }, - { countryCode: 'ID', value: '62', label: 'Indonesia (+62)' }, - { countryCode: 'IR', value: '98', label: 'Iran (+98)' }, - { countryCode: 'IQ', value: '964', label: 'Iraq (+964)' }, - { countryCode: 'IE', value: '353', label: 'Ireland (+353)' }, - { countryCode: 'IL', value: '972', label: 'Israel (+972)' }, - { countryCode: 'IT', value: '39', label: 'Italy (+39)' }, - { countryCode: 'JM', value: '1876', label: 'Jamaica (+1876)' }, - { countryCode: 'JP', value: '81', label: 'Japan (+81)' }, - { countryCode: 'JO', value: '962', label: 'Jordan (+962)' }, - { countryCode: 'KZ', value: '7', label: 'Kazakhstan (+7)' }, - { countryCode: 'KE', value: '254', label: 'Kenya (+254)' }, - { countryCode: 'KI', value: '686', label: 'Kiribati (+686)' }, - { countryCode: 'KP', value: '850', label: 'Korea North (+850)' }, - { countryCode: 'KR', value: '82', label: 'Korea South (+82)' }, - { countryCode: 'KW', value: '965', label: 'Kuwait (+965)' }, - { countryCode: 'KG', value: '996', label: 'Kyrgyzstan (+996)' }, - { countryCode: 'LA', value: '856', label: 'Laos (+856)' }, - { countryCode: 'LV', value: '371', label: 'Latvia (+371)' }, - { countryCode: 'LB', value: '961', label: 'Lebanon (+961)' }, - { countryCode: 'LS', value: '266', label: 'Lesotho (+266)' }, - { countryCode: 'LR', value: '231', label: 'Liberia (+231)' }, - { countryCode: 'LY', value: '218', label: 'Libya (+218)' }, - { countryCode: 'LI', value: '417', label: 'Liechtenstein (+417)' }, - { countryCode: 'LT', value: '370', label: 'Lithuania (+370)' }, - { countryCode: 'LU', value: '352', label: 'Luxembourg (+352)' }, - { countryCode: 'MO', value: '853', label: 'Macao (+853)' }, - { countryCode: 'MK', value: '389', label: 'Macedonia (+389)' }, - { countryCode: 'MG', value: '261', label: 'Madagascar (+261)' }, - { countryCode: 'MW', value: '265', label: 'Malawi (+265)' }, - { countryCode: 'MY', value: '60', label: 'Malaysia (+60)' }, - { countryCode: 'MV', value: '960', label: 'Maldives (+960)' }, - { countryCode: 'ML', value: '223', label: 'Mali (+223)' }, - { countryCode: 'MT', value: '356', label: 'Malta (+356)' }, - { countryCode: 'MH', value: '692', label: 'Marshall Islands (+692)' }, - { countryCode: 'MQ', value: '596', label: 'Martinique (+596)' }, - { countryCode: 'MR', value: '222', label: 'Mauritania (+222)' }, - { countryCode: 'YT', value: '269', label: 'Mayotte (+269)' }, - { countryCode: 'MX', value: '52', label: 'Mexico (+52)' }, - { countryCode: 'FM', value: '691', label: 'Micronesia (+691)' }, - { countryCode: 'MD', value: '373', label: 'Moldova (+373)' }, - { countryCode: 'MC', value: '377', label: 'Monaco (+377)' }, - { countryCode: 'MN', value: '976', label: 'Mongolia (+976)' }, - { countryCode: 'MS', value: '1664', label: 'Montserrat (+1664)' }, - { countryCode: 'MA', value: '212', label: 'Morocco (+212)' }, - { countryCode: 'MZ', value: '258', label: 'Mozambique (+258)' }, - { countryCode: 'MN', value: '95', label: 'Myanmar (+95)' }, - { countryCode: 'NA', value: '264', label: 'Namibia (+264)' }, - { countryCode: 'NR', value: '674', label: 'Nauru (+674)' }, - { countryCode: 'NP', value: '977', label: 'Nepal (+977)' }, - { countryCode: 'NL', value: '31', label: 'Netherlands (+31)' }, - { countryCode: 'NC', value: '687', label: 'New Caledonia (+687)' }, - { countryCode: 'NZ', value: '64', label: 'New Zealand (+64)' }, - { countryCode: 'NI', value: '505', label: 'Nicaragua (+505)' }, - { countryCode: 'NE', value: '227', label: 'Niger (+227)' }, - { countryCode: 'NG', value: '234', label: 'Nigeria (+234)' }, - { countryCode: 'NU', value: '683', label: 'Niue (+683)' }, - { countryCode: 'NF', value: '672', label: 'Norfolk Islands (+672)' }, - { countryCode: 'NP', value: '670', label: 'Northern Marianas (+670)' }, - { countryCode: 'NO', value: '47', label: 'Norway (+47)' }, - { countryCode: 'OM', value: '968', label: 'Oman (+968)' }, - { countryCode: 'PW', value: '680', label: 'Palau (+680)' }, - { countryCode: 'PA', value: '507', label: 'Panama (+507)' }, - { countryCode: 'PG', value: '675', label: 'Papua New Guinea (+675)' }, - { countryCode: 'PY', value: '595', label: 'Paraguay (+595)' }, - { countryCode: 'PE', value: '51', label: 'Peru (+51)' }, - { countryCode: 'PH', value: '63', label: 'Philippines (+63)' }, - { countryCode: 'PL', value: '48', label: 'Poland (+48)' }, - { countryCode: 'PT', value: '351', label: 'Portugal (+351)' }, - { countryCode: 'PR', value: '1787', label: 'Puerto Rico (+1787)' }, - { countryCode: 'QA', value: '974', label: 'Qatar (+974)' }, - { countryCode: 'RE', value: '262', label: 'Reunion (+262)' }, - { countryCode: 'RO', value: '40', label: 'Romania (+40)' }, - { countryCode: 'RU', value: '7', label: 'Russia (+7)' }, - { countryCode: 'RW', value: '250', label: 'Rwanda (+250)' }, - { countryCode: 'SM', value: '378', label: 'San Marino (+378)' }, - { countryCode: 'ST', value: '239', label: 'Sao Tome & Principe (+239)' }, - { countryCode: 'SA', value: '966', label: 'Saudi Arabia (+966)' }, - { countryCode: 'SN', value: '221', label: 'Senegal (+221)' }, - { countryCode: 'CS', value: '381', label: 'Serbia (+381)' }, - { countryCode: 'SC', value: '248', label: 'Seychelles (+248)' }, - { countryCode: 'SL', value: '232', label: 'Sierra Leone (+232)' }, - { countryCode: 'SG', value: '65', label: 'Singapore (+65)' }, - { countryCode: 'SX', value: '1', label: 'Sint Maarten (+1)' }, - { countryCode: 'SK', value: '421', label: 'Slovak Republic (+421)' }, - { countryCode: 'SI', value: '386', label: 'Slovenia (+386)' }, - { countryCode: 'SB', value: '677', label: 'Solomon Islands (+677)' }, - { countryCode: 'SO', value: '252', label: 'Somalia (+252)' }, - { countryCode: 'ZA', value: '27', label: 'South Africa (+27)' }, - { countryCode: 'ES', value: '34', label: 'Spain (+34)' }, - { countryCode: 'LK', value: '94', label: 'Sri Lanka (+94)' }, - { countryCode: 'SH', value: '290', label: 'St. Helena (+290)' }, - { countryCode: 'KN', value: '1869', label: 'St. Kitts (+1869)' }, - { countryCode: 'SC', value: '1758', label: 'St. Lucia (+1758)' }, - { countryCode: 'SD', value: '249', label: 'Sudan (+249)' }, - { countryCode: 'SR', value: '597', label: 'Suriname (+597)' }, - { countryCode: 'SZ', value: '268', label: 'Swaziland (+268)' }, - { countryCode: 'SE', value: '46', label: 'Sweden (+46)' }, - { countryCode: 'CH', value: '41', label: 'Switzerland (+41)' }, - { countryCode: 'SI', value: '963', label: 'Syria (+963)' }, - { countryCode: 'TW', value: '886', label: 'Taiwan (+886)' }, - { countryCode: 'TJ', value: '7', label: 'Tajikstan (+7)' }, - { countryCode: 'TH', value: '66', label: 'Thailand (+66)' }, - { countryCode: 'TG', value: '228', label: 'Togo (+228)' }, - { countryCode: 'TO', value: '676', label: 'Tonga (+676)' }, - { countryCode: 'TT', value: '1868', label: 'Trinidad & Tobago (+1868)' }, - { countryCode: 'TN', value: '216', label: 'Tunisia (+216)' }, - { countryCode: 'TR', value: '90', label: 'Turkey (+90)' }, - { countryCode: 'TM', value: '7', label: 'Turkmenistan (+7)' }, - { countryCode: 'TM', value: '993', label: 'Turkmenistan (+993)' }, - { countryCode: 'TC', value: '1649', label: 'Turks & Caicos Islands (+1649)' }, - { countryCode: 'TV', value: '688', label: 'Tuvalu (+688)' }, - { countryCode: 'UG', value: '256', label: 'Uganda (+256)' }, - { countryCode: 'UA', value: '380', label: 'Ukraine (+380)' }, - { countryCode: 'AE', value: '971', label: 'United Arab Emirates (+971)' }, - { countryCode: 'UY', value: '598', label: 'Uruguay (+598)' }, - { countryCode: 'UZ', value: '7', label: 'Uzbekistan (+7)' }, - { countryCode: 'VU', value: '678', label: 'Vanuatu (+678)' }, - { countryCode: 'VA', value: '379', label: 'Vatican City (+379)' }, - { countryCode: 'VE', value: '58', label: 'Venezuela (+58)' }, - { countryCode: 'VN', value: '84', label: 'Vietnam (+84)' }, - { countryCode: 'VG', value: '84', label: 'Virgin Islands - British (+1284)' }, - { countryCode: 'VI', value: '84', label: 'Virgin Islands - US (+1340)' }, - { countryCode: 'WF', value: '681', label: 'Wallis and Futuna (+681)' }, - { countryCode: 'YE', value: '969', label: 'Yemen (North) (+969)' }, - { countryCode: 'YE', value: '967', label: 'Yemen (South) (+967)' }, - { countryCode: 'ZM', value: '260', label: 'Zambia (+260)' }, - { countryCode: 'ZW', value: '263', label: 'Zimbabwe (+263)' }, + { countryCode: 'US', value: '1', label: 'USA (+1)' }, + { countryCode: 'GB', value: '44', label: 'UK (+44)' }, + { countryCode: 'DZ', value: '213', label: 'Algeria (+213)' }, + { countryCode: 'AD', value: '376', label: 'Andorra (+376)' }, + { countryCode: 'AO', value: '244', label: 'Angola (+244)' }, + { countryCode: 'AI', value: '1264', label: 'Anguilla (+1264)' }, + { countryCode: 'AG', value: '1268', label: 'Antigua & Barbuda (+1268)' }, + { countryCode: 'AR', value: '54', label: 'Argentina (+54)' }, + { countryCode: 'AM', value: '374', label: 'Armenia (+374)' }, + { countryCode: 'AW', value: '297', label: 'Aruba (+297)' }, + { countryCode: 'AU', value: '61', label: 'Australia (+61)' }, + { countryCode: 'AT', value: '43', label: 'Austria (+43)' }, + { countryCode: 'AZ', value: '994', label: 'Azerbaijan (+994)' }, + { countryCode: 'BS', value: '1242', label: 'Bahamas (+1242)' }, + { countryCode: 'BH', value: '973', label: 'Bahrain (+973)' }, + { countryCode: 'BD', value: '880', label: 'Bangladesh (+880)' }, + { countryCode: 'BB', value: '1246', label: 'Barbados (+1246)' }, + { countryCode: 'BY', value: '375', label: 'Belarus (+375)' }, + { countryCode: 'BE', value: '32', label: 'Belgium (+32)' }, + { countryCode: 'BZ', value: '501', label: 'Belize (+501)' }, + { countryCode: 'BJ', value: '229', label: 'Benin (+229)' }, + { countryCode: 'BM', value: '1441', label: 'Bermuda (+1441)' }, + { countryCode: 'BT', value: '975', label: 'Bhutan (+975)' }, + { countryCode: 'BO', value: '591', label: 'Bolivia (+591)' }, + { countryCode: 'BA', value: '387', label: 'Bosnia Herzegovina (+387)' }, + { countryCode: 'BW', value: '267', label: 'Botswana (+267)' }, + { countryCode: 'BR', value: '55', label: 'Brazil (+55)' }, + { countryCode: 'BN', value: '673', label: 'Brunei (+673)' }, + { countryCode: 'BG', value: '359', label: 'Bulgaria (+359)' }, + { countryCode: 'BF', value: '226', label: 'Burkina Faso (+226)' }, + { countryCode: 'BI', value: '257', label: 'Burundi (+257)' }, + { countryCode: 'KH', value: '855', label: 'Cambodia (+855)' }, + { countryCode: 'CM', value: '237', label: 'Cameroon (+237)' }, + { countryCode: 'CA', value: '1', label: 'Canada (+1)' }, + { countryCode: 'CV', value: '238', label: 'Cape Verde Islands (+238)' }, + { countryCode: 'KY', value: '1345', label: 'Cayman Islands (+1345)' }, + { countryCode: 'CF', value: '236', label: 'Central African Republic (+236)' }, + { countryCode: 'CL', value: '56', label: 'Chile (+56)' }, + { countryCode: 'CN', value: '86', label: 'China (+86)' }, + { countryCode: 'CO', value: '57', label: 'Colombia (+57)' }, + { countryCode: 'KM', value: '269', label: 'Comoros (+269)' }, + { countryCode: 'CG', value: '242', label: 'Congo (+242)' }, + { countryCode: 'CK', value: '682', label: 'Cook Islands (+682)' }, + { countryCode: 'CR', value: '506', label: 'Costa Rica (+506)' }, + { countryCode: 'HR', value: '385', label: 'Croatia (+385)' }, + { countryCode: 'CU', value: '53', label: 'Cuba (+53)' }, + { countryCode: 'CW', value: '599', label: 'Curacao (+599)' }, + { countryCode: 'CY', value: '90392', label: 'Cyprus North (+90392)' }, + { countryCode: 'CY', value: '357', label: 'Cyprus South (+357)' }, + { countryCode: 'CZ', value: '42', label: 'Czech Republic (+42)' }, + { countryCode: 'DK', value: '45', label: 'Denmark (+45)' }, + { countryCode: 'DJ', value: '253', label: 'Djibouti (+253)' }, + { countryCode: 'DM', value: '1809', label: 'Dominica (+1809)' }, + { countryCode: 'DO', value: '1809', label: 'Dominican Republic (+1809)' }, + { countryCode: 'EC', value: '593', label: 'Ecuador (+593)' }, + { countryCode: 'EG', value: '20', label: 'Egypt (+20)' }, + { countryCode: 'SV', value: '503', label: 'El Salvador (+503)' }, + { countryCode: 'GQ', value: '240', label: 'Equatorial Guinea (+240)' }, + { countryCode: 'ER', value: '291', label: 'Eritrea (+291)' }, + { countryCode: 'EE', value: '372', label: 'Estonia (+372)' }, + { countryCode: 'ET', value: '251', label: 'Ethiopia (+251)' }, + { countryCode: 'FK', value: '500', label: 'Falkland Islands (+500)' }, + { countryCode: 'FO', value: '298', label: 'Faroe Islands (+298)' }, + { countryCode: 'FJ', value: '679', label: 'Fiji (+679)' }, + { countryCode: 'FI', value: '358', label: 'Finland (+358)' }, + { countryCode: 'FR', value: '33', label: 'France (+33)' }, + { countryCode: 'GF', value: '594', label: 'French Guiana (+594)' }, + { countryCode: 'PF', value: '689', label: 'French Polynesia (+689)' }, + { countryCode: 'GA', value: '241', label: 'Gabon (+241)' }, + { countryCode: 'GM', value: '220', label: 'Gambia (+220)' }, + { countryCode: 'GE', value: '7880', label: 'Georgia (+7880)' }, + { countryCode: 'DE', value: '49', label: 'Germany (+49)' }, + { countryCode: 'GH', value: '233', label: 'Ghana (+233)' }, + { countryCode: 'GI', value: '350', label: 'Gibraltar (+350)' }, + { countryCode: 'GR', value: '30', label: 'Greece (+30)' }, + { countryCode: 'GL', value: '299', label: 'Greenland (+299)' }, + { countryCode: 'GD', value: '1473', label: 'Grenada (+1473)' }, + { countryCode: 'GP', value: '590', label: 'Guadeloupe (+590)' }, + { countryCode: 'GU', value: '671', label: 'Guam (+671)' }, + { countryCode: 'GT', value: '502', label: 'Guatemala (+502)' }, + { countryCode: 'GN', value: '224', label: 'Guinea (+224)' }, + { countryCode: 'GW', value: '245', label: 'Guinea - Bissau (+245)' }, + { countryCode: 'GY', value: '592', label: 'Guyana (+592)' }, + { countryCode: 'HT', value: '509', label: 'Haiti (+509)' }, + { countryCode: 'HN', value: '504', label: 'Honduras (+504)' }, + { countryCode: 'HK', value: '852', label: 'Hong Kong (+852)' }, + { countryCode: 'HU', value: '36', label: 'Hungary (+36)' }, + { countryCode: 'IS', value: '354', label: 'Iceland (+354)' }, + { countryCode: 'IN', value: '91', label: 'India (+91)' }, + { countryCode: 'ID', value: '62', label: 'Indonesia (+62)' }, + { countryCode: 'IR', value: '98', label: 'Iran (+98)' }, + { countryCode: 'IQ', value: '964', label: 'Iraq (+964)' }, + { countryCode: 'IE', value: '353', label: 'Ireland (+353)' }, + { countryCode: 'IL', value: '972', label: 'Israel (+972)' }, + { countryCode: 'IT', value: '39', label: 'Italy (+39)' }, + { countryCode: 'JM', value: '1876', label: 'Jamaica (+1876)' }, + { countryCode: 'JP', value: '81', label: 'Japan (+81)' }, + { countryCode: 'JO', value: '962', label: 'Jordan (+962)' }, + { countryCode: 'KZ', value: '7', label: 'Kazakhstan (+7)' }, + { countryCode: 'KE', value: '254', label: 'Kenya (+254)' }, + { countryCode: 'KI', value: '686', label: 'Kiribati (+686)' }, + { countryCode: 'KP', value: '850', label: 'Korea North (+850)' }, + { countryCode: 'KR', value: '82', label: 'Korea South (+82)' }, + { countryCode: 'KW', value: '965', label: 'Kuwait (+965)' }, + { countryCode: 'KG', value: '996', label: 'Kyrgyzstan (+996)' }, + { countryCode: 'LA', value: '856', label: 'Laos (+856)' }, + { countryCode: 'LV', value: '371', label: 'Latvia (+371)' }, + { countryCode: 'LB', value: '961', label: 'Lebanon (+961)' }, + { countryCode: 'LS', value: '266', label: 'Lesotho (+266)' }, + { countryCode: 'LR', value: '231', label: 'Liberia (+231)' }, + { countryCode: 'LY', value: '218', label: 'Libya (+218)' }, + { countryCode: 'LI', value: '417', label: 'Liechtenstein (+417)' }, + { countryCode: 'LT', value: '370', label: 'Lithuania (+370)' }, + { countryCode: 'LU', value: '352', label: 'Luxembourg (+352)' }, + { countryCode: 'MO', value: '853', label: 'Macao (+853)' }, + { countryCode: 'MK', value: '389', label: 'Macedonia (+389)' }, + { countryCode: 'MG', value: '261', label: 'Madagascar (+261)' }, + { countryCode: 'MW', value: '265', label: 'Malawi (+265)' }, + { countryCode: 'MY', value: '60', label: 'Malaysia (+60)' }, + { countryCode: 'MV', value: '960', label: 'Maldives (+960)' }, + { countryCode: 'ML', value: '223', label: 'Mali (+223)' }, + { countryCode: 'MT', value: '356', label: 'Malta (+356)' }, + { countryCode: 'MH', value: '692', label: 'Marshall Islands (+692)' }, + { countryCode: 'MQ', value: '596', label: 'Martinique (+596)' }, + { countryCode: 'MR', value: '222', label: 'Mauritania (+222)' }, + { countryCode: 'YT', value: '269', label: 'Mayotte (+269)' }, + { countryCode: 'MX', value: '52', label: 'Mexico (+52)' }, + { countryCode: 'FM', value: '691', label: 'Micronesia (+691)' }, + { countryCode: 'MD', value: '373', label: 'Moldova (+373)' }, + { countryCode: 'MC', value: '377', label: 'Monaco (+377)' }, + { countryCode: 'MN', value: '976', label: 'Mongolia (+976)' }, + { countryCode: 'MS', value: '1664', label: 'Montserrat (+1664)' }, + { countryCode: 'MA', value: '212', label: 'Morocco (+212)' }, + { countryCode: 'MZ', value: '258', label: 'Mozambique (+258)' }, + { countryCode: 'MN', value: '95', label: 'Myanmar (+95)' }, + { countryCode: 'NA', value: '264', label: 'Namibia (+264)' }, + { countryCode: 'NR', value: '674', label: 'Nauru (+674)' }, + { countryCode: 'NP', value: '977', label: 'Nepal (+977)' }, + { countryCode: 'NL', value: '31', label: 'Netherlands (+31)' }, + { countryCode: 'NC', value: '687', label: 'New Caledonia (+687)' }, + { countryCode: 'NZ', value: '64', label: 'New Zealand (+64)' }, + { countryCode: 'NI', value: '505', label: 'Nicaragua (+505)' }, + { countryCode: 'NE', value: '227', label: 'Niger (+227)' }, + { countryCode: 'NG', value: '234', label: 'Nigeria (+234)' }, + { countryCode: 'NU', value: '683', label: 'Niue (+683)' }, + { countryCode: 'NF', value: '672', label: 'Norfolk Islands (+672)' }, + { countryCode: 'NP', value: '670', label: 'Northern Marianas (+670)' }, + { countryCode: 'NO', value: '47', label: 'Norway (+47)' }, + { countryCode: 'OM', value: '968', label: 'Oman (+968)' }, + { countryCode: 'PW', value: '680', label: 'Palau (+680)' }, + { countryCode: 'PA', value: '507', label: 'Panama (+507)' }, + { countryCode: 'PG', value: '675', label: 'Papua New Guinea (+675)' }, + { countryCode: 'PY', value: '595', label: 'Paraguay (+595)' }, + { countryCode: 'PE', value: '51', label: 'Peru (+51)' }, + { countryCode: 'PH', value: '63', label: 'Philippines (+63)' }, + { countryCode: 'PL', value: '48', label: 'Poland (+48)' }, + { countryCode: 'PT', value: '351', label: 'Portugal (+351)' }, + { countryCode: 'PR', value: '1787', label: 'Puerto Rico (+1787)' }, + { countryCode: 'QA', value: '974', label: 'Qatar (+974)' }, + { countryCode: 'RE', value: '262', label: 'Reunion (+262)' }, + { countryCode: 'RO', value: '40', label: 'Romania (+40)' }, + { countryCode: 'RU', value: '7', label: 'Russia (+7)' }, + { countryCode: 'RW', value: '250', label: 'Rwanda (+250)' }, + { countryCode: 'SM', value: '378', label: 'San Marino (+378)' }, + { countryCode: 'ST', value: '239', label: 'Sao Tome & Principe (+239)' }, + { countryCode: 'SA', value: '966', label: 'Saudi Arabia (+966)' }, + { countryCode: 'SN', value: '221', label: 'Senegal (+221)' }, + { countryCode: 'CS', value: '381', label: 'Serbia (+381)' }, + { countryCode: 'SC', value: '248', label: 'Seychelles (+248)' }, + { countryCode: 'SL', value: '232', label: 'Sierra Leone (+232)' }, + { countryCode: 'SG', value: '65', label: 'Singapore (+65)' }, + { countryCode: 'SX', value: '1', label: 'Sint Maarten (+1)' }, + { countryCode: 'SK', value: '421', label: 'Slovak Republic (+421)' }, + { countryCode: 'SI', value: '386', label: 'Slovenia (+386)' }, + { countryCode: 'SB', value: '677', label: 'Solomon Islands (+677)' }, + { countryCode: 'SO', value: '252', label: 'Somalia (+252)' }, + { countryCode: 'ZA', value: '27', label: 'South Africa (+27)' }, + { countryCode: 'ES', value: '34', label: 'Spain (+34)' }, + { countryCode: 'LK', value: '94', label: 'Sri Lanka (+94)' }, + { countryCode: 'SH', value: '290', label: 'St. Helena (+290)' }, + { countryCode: 'KN', value: '1869', label: 'St. Kitts (+1869)' }, + { countryCode: 'SC', value: '1758', label: 'St. Lucia (+1758)' }, + { countryCode: 'SD', value: '249', label: 'Sudan (+249)' }, + { countryCode: 'SR', value: '597', label: 'Suriname (+597)' }, + { countryCode: 'SZ', value: '268', label: 'Swaziland (+268)' }, + { countryCode: 'SE', value: '46', label: 'Sweden (+46)' }, + { countryCode: 'CH', value: '41', label: 'Switzerland (+41)' }, + { countryCode: 'SI', value: '963', label: 'Syria (+963)' }, + { countryCode: 'TW', value: '886', label: 'Taiwan (+886)' }, + { countryCode: 'TJ', value: '7', label: 'Tajikstan (+7)' }, + { countryCode: 'TH', value: '66', label: 'Thailand (+66)' }, + { countryCode: 'TG', value: '228', label: 'Togo (+228)' }, + { countryCode: 'TO', value: '676', label: 'Tonga (+676)' }, + { countryCode: 'TT', value: '1868', label: 'Trinidad & Tobago (+1868)' }, + { countryCode: 'TN', value: '216', label: 'Tunisia (+216)' }, + { countryCode: 'TR', value: '90', label: 'Turkey (+90)' }, + { countryCode: 'TM', value: '7', label: 'Turkmenistan (+7)' }, + { countryCode: 'TM', value: '993', label: 'Turkmenistan (+993)' }, + { countryCode: 'TC', value: '1649', label: 'Turks & Caicos Islands (+1649)' }, + { countryCode: 'TV', value: '688', label: 'Tuvalu (+688)' }, + { countryCode: 'UG', value: '256', label: 'Uganda (+256)' }, + { countryCode: 'UA', value: '380', label: 'Ukraine (+380)' }, + { countryCode: 'AE', value: '971', label: 'United Arab Emirates (+971)' }, + { countryCode: 'UY', value: '598', label: 'Uruguay (+598)' }, + { countryCode: 'UZ', value: '7', label: 'Uzbekistan (+7)' }, + { countryCode: 'VU', value: '678', label: 'Vanuatu (+678)' }, + { countryCode: 'VA', value: '379', label: 'Vatican City (+379)' }, + { countryCode: 'VE', value: '58', label: 'Venezuela (+58)' }, + { countryCode: 'VN', value: '84', label: 'Vietnam (+84)' }, + { countryCode: 'VG', value: '84', label: 'Virgin Islands - British (+1284)' }, + { countryCode: 'VI', value: '84', label: 'Virgin Islands - US (+1340)' }, + { countryCode: 'WF', value: '681', label: 'Wallis and Futuna (+681)' }, + { countryCode: 'YE', value: '969', label: 'Yemen (North) (+969)' }, + { countryCode: 'YE', value: '967', label: 'Yemen (South) (+967)' }, + { countryCode: 'ZM', value: '260', label: 'Zambia (+260)' }, + { countryCode: 'ZW', value: '263', label: 'Zimbabwe (+263)' }, ]; export default countries; diff --git a/packages/aws-amplify-vue/src/assets/data-test-attributes.js b/packages/aws-amplify-vue/src/assets/data-test-attributes.js index 124f9569215..0319edd571d 100644 --- a/packages/aws-amplify-vue/src/assets/data-test-attributes.js +++ b/packages/aws-amplify-vue/src/assets/data-test-attributes.js @@ -1,163 +1,162 @@ // Auth const signIn = { - section: 'sign-in-section', - headerSection: 'sign-in-header-section', - bodySection: 'sign-in-body-section', - footerSection: 'sign-in-footer-section', - usernameInput: 'username-input', - passwordInput: 'sign-in-password-input', - forgotPasswordLink: 'sign-in-forgot-password-link', - signInButton: 'sign-in-sign-in-button', - createAccountLink: 'sign-in-create-account-link', - signInError: 'authenticator-error', + section: 'sign-in-section', + headerSection: 'sign-in-header-section', + bodySection: 'sign-in-body-section', + footerSection: 'sign-in-footer-section', + usernameInput: 'username-input', + passwordInput: 'sign-in-password-input', + forgotPasswordLink: 'sign-in-forgot-password-link', + signInButton: 'sign-in-sign-in-button', + createAccountLink: 'sign-in-create-account-link', + signInError: 'authenticator-error', }; const signOut = { - button: 'sign-out-button', - section: 'sign-out-section', + button: 'sign-out-button', + section: 'sign-out-section', }; const signUp = { - section: 'sign-up-section', - headerSection: 'sign-up-header-section', - bodySection: 'sign-up-body-section', - nonPhoneNumberInput: 'sign-up-non-phone-number-input', - phoneNumberInput: 'sign-up-phone-number-input', - dialCodeSelect: 'sign-up-dial-code-select', - footerSection: 'sign-up-footer-section', - createAccountButton: 'sign-up-create-account-button', - signInLink: 'sign-up-sign-in-link', - signUpButton: 'sign-up-sign-up-button', - signInButton: 'sign-up-sign-in-button', - confirmButton: 'sign-up-confirm-button', + section: 'sign-up-section', + headerSection: 'sign-up-header-section', + bodySection: 'sign-up-body-section', + nonPhoneNumberInput: 'sign-up-non-phone-number-input', + phoneNumberInput: 'sign-up-phone-number-input', + dialCodeSelect: 'sign-up-dial-code-select', + footerSection: 'sign-up-footer-section', + createAccountButton: 'sign-up-create-account-button', + signInLink: 'sign-up-sign-in-link', + signUpButton: 'sign-up-sign-up-button', + signInButton: 'sign-up-sign-in-button', + confirmButton: 'sign-up-confirm-button', }; const verifyContact = { - section: 'verify-contact-section', - headerSection: 'verify-contact-header-section', - bodySection: 'verify-contact-body-section', - submitButton: 'verify-contact-submit-button', - verifyButton: 'verify-contact-verify-button', - skipLink: 'verify-contact-skip-link', + section: 'verify-contact-section', + headerSection: 'verify-contact-header-section', + bodySection: 'verify-contact-body-section', + submitButton: 'verify-contact-submit-button', + verifyButton: 'verify-contact-verify-button', + skipLink: 'verify-contact-skip-link', }; const TOTPSetup = { - component: 'totp-setup-component', + component: 'totp-setup-component', }; const requireNewPassword = { - section: 'require-new-password-section', - headerSection: 'require-new-password-header-section', - footerSection:'require-new-password-footer-section', - bodySection:'require-new-password-body-section', - newPasswordInput:'require-new-password-new-password-input', - backToSignInLink:'require-new-password-back-to-sign-in-link', - submitButton: 'require-new-password-submit-button', + section: 'require-new-password-section', + headerSection: 'require-new-password-header-section', + footerSection: 'require-new-password-footer-section', + bodySection: 'require-new-password-body-section', + newPasswordInput: 'require-new-password-new-password-input', + backToSignInLink: 'require-new-password-back-to-sign-in-link', + submitButton: 'require-new-password-submit-button', }; const loading = { - section: 'loading-secton', + section: 'loading-secton', }; const greetings = { - navBar: 'greetings-nav-bar', - nav: 'greetings-nav', - navRight: 'greetings-nav-right' + navBar: 'greetings-nav-bar', + nav: 'greetings-nav', + navRight: 'greetings-nav-right', }; -// TODO: Change Angular Component (Greeting) to match React Component (Greetings) +// TODO: Change Angular Component (Greeting) to match React Component (Greetings) const greeting = { - signOutButton: 'sign-out-button', - signOutLink: 'greeting-sign-out-link', - navRight: 'greetings-nav-right', + signOutButton: 'sign-out-button', + signOutLink: 'greeting-sign-out-link', + navRight: 'greetings-nav-right', }; const federatedSignIn = { - section: 'federated-sign-in-section', - bodySection: 'federated-sign-in-body-section', - signInButtons:'federated-sign-in-buttons', + section: 'federated-sign-in-section', + bodySection: 'federated-sign-in-body-section', + signInButtons: 'federated-sign-in-buttons', }; const confirmSignUp = { - section: 'confirm-sign-up-section', - headerSection: 'confirm-sign-up-header-section', - bodySection: 'confirm-sign-up-body-section', - usernameInput: 'confirm-sign-up-username-input', - confirmationCodeInput: 'confirm-sign-up-confirmation-code-input', - resendCodeLink: 'confirm-sign-up-resend-code-link', - confirmButton: 'confirm-sign-up-confirm-button', - backToSignInLink: 'confirm-sign-up-back-to-sign-in-link' + section: 'confirm-sign-up-section', + headerSection: 'confirm-sign-up-header-section', + bodySection: 'confirm-sign-up-body-section', + usernameInput: 'confirm-sign-up-username-input', + confirmationCodeInput: 'confirm-sign-up-confirmation-code-input', + resendCodeLink: 'confirm-sign-up-resend-code-link', + confirmButton: 'confirm-sign-up-confirm-button', + backToSignInLink: 'confirm-sign-up-back-to-sign-in-link', }; const confirmSignIn = { - section: 'confirm-sign-in-section', - headerSection: 'confirm-sign-in-header-section', - bodySection: 'confirm-sign-in-body-section', - codeInput: 'confirm-sign-in-code-input', - confirmButton: 'confirm-sign-in-confirm-button', - backToSignInLink: 'confirm-sign-in-back-to-sign-in-link', + section: 'confirm-sign-in-section', + headerSection: 'confirm-sign-in-header-section', + bodySection: 'confirm-sign-in-body-section', + codeInput: 'confirm-sign-in-code-input', + confirmButton: 'confirm-sign-in-confirm-button', + backToSignInLink: 'confirm-sign-in-back-to-sign-in-link', }; const setMFAComp = { - section: 'set-mfa-section', - headerSection: 'set-mfa-header-section', - bodySection: 'set-mfa-header-body-section', - smsInput: 'set-mfa-sms-input', - totpInput: 'set-mfa-totp-input', - noMfaInput: 'set-mfa-nomfa-input', - verificationCodeInput: 'set-mfa-verification-code-input', - setMfaButton: 'set-mfa-set-mfa-button', - verifyTotpTokenButton: 'set-mfa-verify-totp-token-button', - cancelButton: 'set-mfa-cancel-button', + section: 'set-mfa-section', + headerSection: 'set-mfa-header-section', + bodySection: 'set-mfa-header-body-section', + smsInput: 'set-mfa-sms-input', + totpInput: 'set-mfa-totp-input', + noMfaInput: 'set-mfa-nomfa-input', + verificationCodeInput: 'set-mfa-verification-code-input', + setMfaButton: 'set-mfa-set-mfa-button', + verifyTotpTokenButton: 'set-mfa-verify-totp-token-button', + cancelButton: 'set-mfa-cancel-button', }; const forgotPassword = { - section: 'forgot-password-section', - headerSection: 'forgot-password-header-section', - bodySection: 'forgot-password-body-section', - submitButton: 'forgot-password-submit-button', - sendCodeButton: 'forgot-password-send-code-button', - resendCodeLink: 'forgot-password-resend-code-link', - backToSignInLink: 'forgot-password-back-to-sign-in-link', - usernameInput: 'username-input', - codeInput: 'forgot-password-code-input', - newPasswordInput: 'forgot-password-new-password-input', + section: 'forgot-password-section', + headerSection: 'forgot-password-header-section', + bodySection: 'forgot-password-body-section', + submitButton: 'forgot-password-submit-button', + sendCodeButton: 'forgot-password-send-code-button', + resendCodeLink: 'forgot-password-resend-code-link', + backToSignInLink: 'forgot-password-back-to-sign-in-link', + usernameInput: 'username-input', + codeInput: 'forgot-password-code-input', + newPasswordInput: 'forgot-password-new-password-input', }; export const sumerianScene = { - container: 'sumerian-scene-container', - sumerianScene: 'sumerian-scene', - loading: 'sumerian-scene-loading', - loadingLogo: 'sumerian-scene-loading-logo', - loadingSceneName: 'sumerian-scene-loading-scene-name', - loadingBar: 'sumerian-scene-loading-bar', - errorText: 'sumerian-scene-error-text', - bar: 'sumerian-scene-bar', - actions: 'sumerian-scene-actions', + container: 'sumerian-scene-container', + sumerianScene: 'sumerian-scene', + loading: 'sumerian-scene-loading', + loadingLogo: 'sumerian-scene-loading-logo', + loadingSceneName: 'sumerian-scene-loading-scene-name', + loadingBar: 'sumerian-scene-loading-bar', + errorText: 'sumerian-scene-error-text', + bar: 'sumerian-scene-bar', + actions: 'sumerian-scene-actions', }; export const genericAttrs = { - usernameInput: 'username-input', - emailInput: 'email-input', - phoneNumberInput: 'phone-number-input', - dialCodeSelect: 'dial-code-select', + usernameInput: 'username-input', + emailInput: 'email-input', + phoneNumberInput: 'phone-number-input', + dialCodeSelect: 'dial-code-select', }; - export const auth = { - signIn, - signOut, - signUp, - verifyContact, - TOTPSetup, - requireNewPassword, - loading, - genericAttrs, - greetings, - greeting, - federatedSignIn, - confirmSignUp, - confirmSignIn, - setMFAComp, - forgotPassword, + signIn, + signOut, + signUp, + verifyContact, + TOTPSetup, + requireNewPassword, + loading, + genericAttrs, + greetings, + greeting, + federatedSignIn, + confirmSignUp, + confirmSignIn, + setMFAComp, + forgotPassword, }; diff --git a/packages/aws-amplify-vue/src/assets/default-sign-up-fields.js b/packages/aws-amplify-vue/src/assets/default-sign-up-fields.js index ea0b6a80c3b..1aa92035c22 100644 --- a/packages/aws-amplify-vue/src/assets/default-sign-up-fields.js +++ b/packages/aws-amplify-vue/src/assets/default-sign-up-fields.js @@ -1,85 +1,84 @@ - export default [ - { - label: 'Username', - key: 'username', - required: true, - placeholder: 'Username', - displayOrder: 1, - }, - { - label: 'Password', - key: 'password', - required: true, - placeholder: 'Password', - type: 'password', - displayOrder: 2, - }, - { - label: 'Email', - key: 'email', - required: true, - placeholder: 'Email', - type: 'email', - displayOrder: 3 - }, - { - label: 'Phone Number', - key: 'phone_number', - placeholder: 'Phone Number', - required: true, - displayOrder: 4 - } + { + label: 'Username', + key: 'username', + required: true, + placeholder: 'Username', + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + placeholder: 'Password', + type: 'password', + displayOrder: 2, + }, + { + label: 'Email', + key: 'email', + required: true, + placeholder: 'Email', + type: 'email', + displayOrder: 3, + }, + { + label: 'Phone Number', + key: 'phone_number', + placeholder: 'Phone Number', + required: true, + displayOrder: 4, + }, ]; export const signUpWithEmailFields = [ - { - label: 'Email', - key: 'email', - required: true, - placeholder: 'Email', - type: 'email', - displayOrder: 1 - }, - { - label: 'Password', - key: 'password', - required: true, - placeholder: 'Password', - type: 'password', - displayOrder: 2, - }, - { - label: 'Phone Number', - key: 'phone_number', - placeholder: 'Phone Number', - required: true, - displayOrder: 3 - } + { + label: 'Email', + key: 'email', + required: true, + placeholder: 'Email', + type: 'email', + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + placeholder: 'Password', + type: 'password', + displayOrder: 2, + }, + { + label: 'Phone Number', + key: 'phone_number', + placeholder: 'Phone Number', + required: true, + displayOrder: 3, + }, ]; export const signUpWithPhoneNumberFields = [ - { - label: 'Phone Number', - key: 'phone_number', - placeholder: 'Phone Number', - required: true, - displayOrder: 1 - }, - { - label: 'Password', - key: 'password', - required: true, - placeholder: 'Password', - type: 'password', - displayOrder: 2 - }, - { - label: 'Email', - key: 'email', - required: true, - placeholder: 'Email', - type: 'email', - displayOrder: 3 - }, + { + label: 'Phone Number', + key: 'phone_number', + placeholder: 'Phone Number', + required: true, + displayOrder: 1, + }, + { + label: 'Password', + key: 'password', + required: true, + placeholder: 'Password', + type: 'password', + displayOrder: 2, + }, + { + label: 'Email', + key: 'email', + required: true, + placeholder: 'Email', + type: 'email', + displayOrder: 3, + }, ]; diff --git a/packages/aws-amplify-vue/src/components/api/index.js b/packages/aws-amplify-vue/src/components/api/index.js index 96681a39fdc..ba105844819 100644 --- a/packages/aws-amplify-vue/src/components/api/index.js +++ b/packages/aws-amplify-vue/src/components/api/index.js @@ -3,6 +3,4 @@ import Connect from './graphql/Connect.vue'; Vue.component('amplify-connect', Connect); -export { - Connect -}; \ No newline at end of file +export { Connect }; diff --git a/packages/aws-amplify-vue/src/components/authenticator/common.js b/packages/aws-amplify-vue/src/components/authenticator/common.js index 081cb04c876..98679e33897 100644 --- a/packages/aws-amplify-vue/src/components/authenticator/common.js +++ b/packages/aws-amplify-vue/src/components/authenticator/common.js @@ -12,11 +12,11 @@ */ export const labelMap = { - email: 'Email', - phone_number: 'Phone Number', - username: 'Username' + email: 'Email', + phone_number: 'Phone Number', + username: 'Username', }; export const composePhoneNumber = (countryCode, local_phone_number) => { - return `+${countryCode}${local_phone_number.replace(/[-()]/g, '')}`; -} + return `+${countryCode}${local_phone_number.replace(/[-()]/g, '')}`; +}; diff --git a/packages/aws-amplify-vue/src/components/authenticator/index.js b/packages/aws-amplify-vue/src/components/authenticator/index.js index 939709a023e..484191ab834 100644 --- a/packages/aws-amplify-vue/src/components/authenticator/index.js +++ b/packages/aws-amplify-vue/src/components/authenticator/index.js @@ -25,7 +25,6 @@ import Authenticator from './Authenticator.vue'; import SetMfa from './SetMFA.vue'; import RequireNewPassword from './RequireNewPassword.vue'; - Vue.component('amplify-authenticator', Authenticator); Vue.component('amplify-sign-in', SignIn); Vue.component('amplify-sign-up', SignUp); @@ -36,15 +35,14 @@ Vue.component('amplify-forgot-password', ForgotPassword); Vue.component('amplify-set-mfa', SetMfa); Vue.component('amplify-require-new-password', RequireNewPassword); - export { - Authenticator, - SignIn, - SignUp, - SignOut, - ConfirmSignUp, - ConfirmSignIn, - ForgotPassword, - SetMfa, - RequireNewPassword, + Authenticator, + SignIn, + SignUp, + SignOut, + ConfirmSignUp, + ConfirmSignIn, + ForgotPassword, + SetMfa, + RequireNewPassword, }; diff --git a/packages/aws-amplify-vue/src/components/interactions/aws-lex-audio.js b/packages/aws-amplify-vue/src/components/interactions/aws-lex-audio.js index 9c64b88dcb3..42740dcaff5 100644 --- a/packages/aws-amplify-vue/src/components/interactions/aws-lex-audio.js +++ b/packages/aws-amplify-vue/src/components/interactions/aws-lex-audio.js @@ -12,793 +12,977 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o amplitude || curr_value_time < (-1 * amplitude)) { - start = Date.now(); - } - } - var newtime = Date.now(); - var elapsedTime = newtime - start; - if (elapsedTime > time) { - silenceCallback(); - } - }; - - /** - * The onaudioprocess event handler of the ScriptProcessorNode interface. It is the EventHandler to be - * called for the audioprocess event that is dispatched to ScriptProcessorNode node types. - * @param {AudioProcessingEvent} audioProcessingEvent - The audio processing event. - */ - node.onaudioprocess = function (audioProcessingEvent) { - if (!recording) { - return; - } - worker.postMessage({ - command: 'record', - buffer: [ - audioProcessingEvent.inputBuffer.getChannelData(0), - ] - }); - analyse(); - }; - - var analyser = source.context.createAnalyser(); - analyser.minDecibels = -90; - analyser.maxDecibels = -10; - analyser.smoothingTimeConstant = 0.85; - - source.connect(analyser); - analyser.connect(node); - node.connect(source.context.destination); - - return { - record: record, - stop: stop, - clear: clear, - exportWAV: exportWAV - }; - }; - - /** - * Audio recorder object. Handles setting up the audio context, - * accessing the mike, and creating the Recorder object. - */ - exports.audioRecorder = function () { - - /** - * Creates an audio context and calls getUserMedia to request the mic (audio). - */ - var requestDevice = function () { - - if (typeof audio_context === 'undefined') { - window.AudioContext = window.AudioContext || window.webkitAudioContext; - audio_context = new AudioContext(); - } - - return navigator.mediaDevices.getUserMedia({audio: true}).then(function (stream) { - audio_stream = stream; - }); - }; - - var createRecorder = function (silenceDetectionConfig) { - return recorder(audio_context.createMediaStreamSource(audio_stream), silenceDetectionConfig); - }; - - var audioContext = function () { - return audio_context; - }; - - return { - requestDevice: requestDevice, - createRecorder: createRecorder, - audioContext: audioContext - }; - - }; -})(); -},{"./worker.js":6,"webworkify":4}],6:[function(require,module,exports){ -module.exports = function (self) { - 'use strict'; - var recLength = 0, - recBuffer = [], - recordSampleRate; - - self.addEventListener('message', function (e) { - switch (e.data.command) { - case 'init': - init(e.data.config); - break; - case 'record': - record(e.data.buffer); - break; - case 'export': - exportBuffer(e.data.sampleRate); - break; - case 'clear': - clear(); - break; - } - }); - - function init(config) { - recordSampleRate = config.sampleRate; - } - - function record(inputBuffer) { - recBuffer.push(inputBuffer[0]); - recLength += inputBuffer[0].length; - } - - function exportBuffer(exportSampleRate) { - var mergedBuffers = mergeBuffers(recBuffer, recLength); - var downsampledBuffer = downsampleBuffer(mergedBuffers, exportSampleRate); - var encodedWav = encodeWAV(downsampledBuffer); - var audioBlob = new Blob([encodedWav], {type: 'application/octet-stream'}); - postMessage(audioBlob); - } - - function clear() { - recLength = 0; - recBuffer = []; - } - - function downsampleBuffer(buffer, exportSampleRate) { - if (exportSampleRate === recordSampleRate) { - return buffer; - } - var sampleRateRatio = recordSampleRate / exportSampleRate; - var newLength = Math.round(buffer.length / sampleRateRatio); - var result = new Float32Array(newLength); - var offsetResult = 0; - var offsetBuffer = 0; - while (offsetResult < result.length) { - var nextOffsetBuffer = Math.round((offsetResult + 1) * sampleRateRatio); - var accum = 0, - count = 0; - for (var i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) { - accum += buffer[i]; - count++; - } - result[offsetResult] = accum / count; - offsetResult++; - offsetBuffer = nextOffsetBuffer; - } - return result; - } - - function mergeBuffers(bufferArray, recLength) { - var result = new Float32Array(recLength); - var offset = 0; - for (var i = 0; i < bufferArray.length; i++) { - result.set(bufferArray[i], offset); - offset += bufferArray[i].length; - } - return result; - } - - function floatTo16BitPCM(output, offset, input) { - for (var i = 0; i < input.length; i++, offset += 2) { - var s = Math.max(-1, Math.min(1, input[i])); - output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true); - } - } - - function writeString(view, offset, string) { - for (var i = 0; i < string.length; i++) { - view.setUint8(offset + i, string.charCodeAt(i)); - } - } - - function encodeWAV(samples) { - var buffer = new ArrayBuffer(44 + samples.length * 2); - var view = new DataView(buffer); - - writeString(view, 0, 'RIFF'); - view.setUint32(4, 32 + samples.length * 2, true); - writeString(view, 8, 'WAVE'); - writeString(view, 12, 'fmt '); - view.setUint32(16, 16, true); - view.setUint16(20, 1, true); - view.setUint16(22, 1, true); - view.setUint32(24, recordSampleRate, true); - view.setUint32(28, recordSampleRate * 2, true); - view.setUint16(32, 2, true); - view.setUint16(34, 16, true); - writeString(view, 36, 'data'); - view.setUint32(40, samples.length * 2, true); - floatTo16BitPCM(view, 44, samples); - - return view; - } -}; - -},{}]},{},[3]); +(function e(t, n, r) { + function s(o, u) { + if (!n[o]) { + if (!t[o]) { + var a = typeof require == 'function' && require; + if (!u && a) return a(o, !0); + if (i) return i(o, !0); + var f = new Error("Cannot find module '" + o + "'"); + throw ((f.code = 'MODULE_NOT_FOUND'), f); + } + var l = (n[o] = { exports: {} }); + t[o][0].call( + l.exports, + function(e) { + var n = t[o][1][e]; + return s(n ? n : e); + }, + l, + l.exports, + e, + t, + n, + r + ); + } + return n[o].exports; + } + var i = typeof require == 'function' && require; + for (var o = 0; o < r.length; o++) s(r[o]); + return s; +})( + { + 1: [ + function(require, module, exports) { + (function() { + 'use strict'; + var rec = require('./recorder.js'); + var recorder, + audioRecorder, + checkAudioSupport, + audioSupported, + playbackSource, + UNSUPPORTED = 'Audio is not supported.'; + + /** + * Represents an audio control that can start and stop recording, + * export captured audio, play an audio buffer, and check if audio + * is supported. + */ + exports.audioControl = function(options) { + options = options || {}; + this.checkAudioSupport = options.checkAudioSupport !== false; + + /** + * This callback type is called `onSilenceCallback`. + * + * @callback onSilenceCallback + */ + + /** + * Visualize callback: `visualizerCallback`. + * + * @callback visualizerCallback + * @param {Uint8Array} dataArray + * @param {number} bufferLength + */ + + /** + * Clears the previous buffer and starts buffering audio. + * + * @param {?onSilenceCallback} onSilence - Called when silence is detected. + * @param {?visualizerCallback} visualizer - Can be used to visualize the captured buffer. + * @param {silenceDetectionConfig} - Specify custom silence detection values. + * @throws {Error} If audio is not supported. + */ + var startRecording = function( + onSilence, + visualizer, + silenceDetectionConfig + ) { + onSilence = + onSilence || + function() { + /* no op */ + }; + visualizer = + visualizer || + function() { + /* no op */ + }; + audioSupported = audioSupported !== false; + if (!audioSupported) { + throw new Error(UNSUPPORTED); + } + recorder = audioRecorder.createRecorder(silenceDetectionConfig); + recorder.record(onSilence, visualizer); + }; + + /** + * Stops buffering audio. + * + * @throws {Error} If audio is not supported. + */ + var stopRecording = function() { + audioSupported = audioSupported !== false; + if (!audioSupported) { + throw new Error(UNSUPPORTED); + } + recorder.stop(); + }; + + /** + * On export complete callback: `onExportComplete`. + * + * @callback onExportComplete + * @param {Blob} blob The exported audio as a Blob. + */ + + /** + * Exports the captured audio buffer. + * + * @param {onExportComplete} callback - Called when the export is complete. + * @param {sampleRate} The sample rate to use in the export. + * @throws {Error} If audio is not supported. + */ + var exportWAV = function(callback, sampleRate) { + audioSupported = audioSupported !== false; + if (!audioSupported) { + throw new Error(UNSUPPORTED); + } + if (!(callback && typeof callback === 'function')) { + throw new Error('You must pass a callback function to export.'); + } + sampleRate = + typeof sampleRate !== 'undefined' ? sampleRate : 16000; + recorder.exportWAV(callback, sampleRate); + recorder.clear(); + }; + + /** + * On playback complete callback: `onPlaybackComplete`. + * + * @callback onPlaybackComplete + */ + + /** + * Plays the audio buffer with an HTML5 audio tag. + * @param {Uint8Array} buffer - The audio buffer to play. + * @param {?onPlaybackComplete} callback - Called when audio playback is complete. + */ + var playHtmlAudioElement = function(buffer, callback) { + if (typeof buffer === 'undefined') { + return; + } + var myBlob = new Blob([buffer]); + var audio = document.createElement('audio'); + var objectUrl = window.URL.createObjectURL(myBlob); + audio.src = objectUrl; + audio.addEventListener('ended', function() { + audio.currentTime = 0; + if (typeof callback === 'function') { + callback(); + } + }); + audio.play(); + }; + + /** + * On playback complete callback: `onPlaybackComplete`. + * + * @callback onPlaybackComplete + */ + + /** + * Plays the audio buffer with a WebAudio AudioBufferSourceNode. + * @param {Uint8Array} buffer - The audio buffer to play. + * @param {?onPlaybackComplete} callback - Called when audio playback is complete. + */ + var play = function(buffer, callback) { + if (typeof buffer === 'undefined') { + return; + } + var myBlob = new Blob([buffer]); + // We'll use a FileReader to create and ArrayBuffer out of the audio response. + var fileReader = new FileReader(); + fileReader.onload = function() { + // Once we have an ArrayBuffer we can create our BufferSource and decode the result as an AudioBuffer. + playbackSource = audioRecorder + .audioContext() + .createBufferSource(); + audioRecorder + .audioContext() + .decodeAudioData(this.result, function(buf) { + // Set the source buffer as our new AudioBuffer. + playbackSource.buffer = buf; + // Set the destination (the actual audio-rendering device--your device's speakers). + playbackSource.connect( + audioRecorder.audioContext().destination + ); + // Add an "on ended" callback. + playbackSource.onended = function(event) { + if (typeof callback === 'function') { + callback(); + } + }; + // Start the playback. + playbackSource.start(0); + }); + }; + fileReader.readAsArrayBuffer(myBlob); + }; + + /** + * Stops the playback source (created by the play method) if it exists. The `onPlaybackComplete` + * callback will be called. + */ + var stop = function() { + if (typeof playbackSource === 'undefined') { + return; + } + playbackSource.stop(); + }; + + /** + * Clear the recording buffer. + */ + var clear = function() { + recorder.clear(); + }; + + /** + * On audio supported callback: `onAudioSupported`. + * + * @callback onAudioSupported + * @param {boolean} + */ + + /** + * Checks that getUserMedia is supported and the user has given us access to the mic. + * @param {onAudioSupported} callback - Called with the result. + */ + var supportsAudio = function(callback) { + callback = + callback || + function() { + /* no op */ + }; + if ( + navigator.mediaDevices && + navigator.mediaDevices.getUserMedia + ) { + audioRecorder = rec.audioRecorder(); + audioRecorder + .requestDevice() + .then(function(stream) { + audioSupported = true; + callback(audioSupported); + }) + .catch(function(error) { + audioSupported = false; + callback(audioSupported); + }); + } else { + audioSupported = false; + callback(audioSupported); + } + }; + + if (this.checkAudioSupport) { + supportsAudio(); + } + + return { + startRecording: startRecording, + stopRecording: stopRecording, + exportWAV: exportWAV, + play: play, + stop: stop, + clear: clear, + playHtmlAudioElement: playHtmlAudioElement, + supportsAudio: supportsAudio, + }; + }; + })(); + }, + { './recorder.js': 5 }, + ], + 2: [ + function(require, module, exports) { + (function() { + 'use strict'; + var AudioControl = require('./control.js').audioControl; + + var DEFAULT_LATEST = '$LATEST'; + var DEFAULT_CONTENT_TYPE = 'audio/x-l16; sample-rate=16000'; + var DEFAULT_USER_ID = 'userId'; + var DEFAULT_ACCEPT_HEADER_VALUE = 'audio/mpeg'; + var MESSAGES = Object.freeze({ + PASSIVE: 'Passive', + LISTENING: 'Listening', + SENDING: 'Sending', + SPEAKING: 'Speaking', + }); + + var lexruntime, + audioControl = new AudioControl({ checkAudioSupport: false }); + + exports.conversation = function( + config, + onStateChange, + onSuccess, + onError, + onAudioData + ) { + var currentState; + + // Apply default values. + this.config = applyDefaults(config); + this.lexConfig = this.config.lexConfig; + this.messages = MESSAGES; + onStateChange = + onStateChange || + function() { + /* no op */ + }; + this.onSuccess = + onSuccess || + function() { + /* no op */ + }; + this.onError = + onError || + function() { + /* no op */ + }; + this.onAudioData = + onAudioData || + function() { + /* no op */ + }; + + // Validate input. + if (!this.config.lexConfig.botName) { + this.onError('A Bot name must be provided.'); + return; + } + if (!AWS.config.credentials) { + this.onError('AWS Credentials must be provided.'); + return; + } + if (!AWS.config.region) { + this.onError('A Region value must be provided.'); + return; + } + + lexruntime = new AWS.LexRuntime(); + + this.onSilence = function() { + if (config.silenceDetection) { + audioControl.stopRecording(); + currentState.advanceConversation(); + } + }; + + this.transition = function(conversation) { + currentState = conversation; + var state = currentState.state; + onStateChange(state.message); + + // If we are transitioning into SENDING or SPEAKING we want to immediately advance the conversation state + // to start the service call or playback. + if ( + state.message === state.messages.SENDING || + state.message === state.messages.SPEAKING + ) { + currentState.advanceConversation(); + } + // If we are transitioning in to sending and we are not detecting silence (this was a manual state change) + // we need to do some cleanup: stop recording, and stop rendering. + if ( + state.message === state.messages.SENDING && + !this.config.silenceDetection + ) { + audioControl.stopRecording(); + } + }; + + this.advanceConversation = function() { + audioControl.supportsAudio(function(supported) { + if (supported) { + currentState.advanceConversation(); + } else { + onError('Audio is not supported.'); + } + }); + }; + + this.updateConfig = function(newValue) { + this.config = applyDefaults(newValue); + this.lexConfig = this.config.lexConfig; + }; + + this.reset = function() { + audioControl.clear(); + currentState = new Initial(currentState.state); + }; + + currentState = new Initial(this); + + return { + advanceConversation: this.advanceConversation, + updateConfig: this.updateConfig, + reset: this.reset, + }; + }; + + var Initial = function(state) { + this.state = state; + state.message = state.messages.PASSIVE; + this.advanceConversation = function() { + audioControl.startRecording( + state.onSilence, + state.onAudioData, + state.config.silenceDetectionConfig + ); + state.transition(new Listening(state)); + }; + }; + + var Listening = function(state) { + this.state = state; + state.message = state.messages.LISTENING; + this.advanceConversation = function() { + audioControl.exportWAV(function(blob) { + state.audioInput = blob; + state.transition(new Sending(state)); + }); + }; + }; + + var Sending = function(state) { + this.state = state; + state.message = state.messages.SENDING; + this.advanceConversation = function() { + state.lexConfig.inputStream = state.audioInput; + lexruntime.postContent(state.lexConfig, function(err, data) { + if (err) { + state.onError(err); + state.transition(new Initial(state)); + } else { + state.audioOutput = data; + state.transition(new Speaking(state)); + state.onSuccess(data); + } + }); + }; + }; + + var Speaking = function(state) { + this.state = state; + state.message = state.messages.SPEAKING; + this.advanceConversation = function() { + if (state.audioOutput.contentType === 'audio/mpeg') { + audioControl.play(state.audioOutput.audioStream, function() { + if ( + state.audioOutput.dialogState === 'ReadyForFulfillment' || + state.audioOutput.dialogState === 'Fulfilled' || + state.audioOutput.dialogState === 'Failed' || + !state.config.silenceDetection + ) { + state.transition(new Initial(state)); + } else { + audioControl.startRecording( + state.onSilence, + state.onAudioData, + state.config.silenceDetectionConfig + ); + state.transition(new Listening(state)); + } + }); + } else { + state.transition(new Initial(state)); + } + }; + }; + + var applyDefaults = function(config) { + config = config || {}; + config.silenceDetection = config.hasOwnProperty('silenceDetection') + ? config.silenceDetection + : true; + + var lexConfig = config.lexConfig || {}; + lexConfig.botAlias = lexConfig.hasOwnProperty('botAlias') + ? lexConfig.botAlias + : DEFAULT_LATEST; + lexConfig.botName = lexConfig.hasOwnProperty('botName') + ? lexConfig.botName + : ''; + lexConfig.contentType = lexConfig.hasOwnProperty('contentType') + ? lexConfig.contentType + : DEFAULT_CONTENT_TYPE; + lexConfig.userId = lexConfig.hasOwnProperty('userId') + ? lexConfig.userId + : DEFAULT_USER_ID; + lexConfig.accept = lexConfig.hasOwnProperty('accept') + ? lexConfig.accept + : DEFAULT_ACCEPT_HEADER_VALUE; + config.lexConfig = lexConfig; + + return config; + }; + })(); + }, + { './control.js': 1 }, + ], + 3: [ + function(require, module, exports) { + (function(global) { + /** + * @module LexAudio + * @description The global namespace for Amazon Lex Audio + */ + global.LexAudio = global.LexAudio || {}; + global.LexAudio.audioControl = require('./control.js').audioControl; + global.LexAudio.conversation = require('./conversation.js').conversation; + module.exports = global.LexAudio; + }.call( + this, + typeof global !== 'undefined' + ? global + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : {} + )); + }, + { './control.js': 1, './conversation.js': 2 }, + ], + 4: [ + function(require, module, exports) { + var bundleFn = arguments[3]; + var sources = arguments[4]; + var cache = arguments[5]; + + var stringify = JSON.stringify; + + module.exports = function(fn, options) { + var wkey; + var cacheKeys = Object.keys(cache); + + for (var i = 0, l = cacheKeys.length; i < l; i++) { + var key = cacheKeys[i]; + var exp = cache[key].exports; + // Using babel as a transpiler to use esmodule, the export will always + // be an object with the default export as a property of it. To ensure + // the existing api and babel esmodule exports are both supported we + // check for both + if (exp === fn || (exp && exp.default === fn)) { + wkey = key; + break; + } + } + + if (!wkey) { + wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); + var wcache = {}; + for (var i = 0, l = cacheKeys.length; i < l; i++) { + var key = cacheKeys[i]; + wcache[key] = key; + } + sources[wkey] = [ + Function(['require', 'module', 'exports'], '(' + fn + ')(self)'), + wcache, + ]; + } + var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); + + var scache = {}; + scache[wkey] = wkey; + sources[skey] = [ + Function( + ['require'], + // try to call default if defined to also support babel esmodule + // exports + 'var f = require(' + + stringify(wkey) + + ');' + + '(f.default ? f.default : f)(self);' + ), + scache, + ]; + + var workerSources = {}; + resolveSources(skey); + + function resolveSources(key) { + workerSources[key] = true; + + for (var depPath in sources[key][1]) { + var depKey = sources[key][1][depPath]; + if (!workerSources[depKey]) { + resolveSources(depKey); + } + } + } + + var src = + '(' + + bundleFn + + ')({' + + Object.keys(workerSources) + .map(function(key) { + return ( + stringify(key) + + ':[' + + sources[key][0] + + ',' + + stringify(sources[key][1]) + + ']' + ); + }) + .join(',') + + '},{},[' + + stringify(skey) + + '])'; + var URL = + window.URL || window.webkitURL || window.mozURL || window.msURL; + + var blob = new Blob([src], { type: 'text/javascript' }); + if (options && options.bare) { + return blob; + } + var workerUrl = URL.createObjectURL(blob); + var worker = new Worker(workerUrl); + worker.objectURL = workerUrl; + return worker; + }; + }, + {}, + ], + 5: [ + function(require, module, exports) { + (function() { + 'use strict'; + var work = require('webworkify'); + var worker = work(require('./worker.js')); + var audio_context, audio_stream; + + /** + * The Recorder object. Sets up the onaudioprocess callback and communicates + * with the web worker to perform audio actions. + */ + var recorder = function(source, silenceDetectionConfig) { + silenceDetectionConfig = silenceDetectionConfig || {}; + silenceDetectionConfig.time = silenceDetectionConfig.hasOwnProperty( + 'time' + ) + ? silenceDetectionConfig.time + : 1500; + silenceDetectionConfig.amplitude = silenceDetectionConfig.hasOwnProperty( + 'amplitude' + ) + ? silenceDetectionConfig.amplitude + : 0.2; + + var recording = false, + currCallback, + start, + silenceCallback, + visualizationCallback; + + // Create a ScriptProcessorNode with a bufferSize of 4096 and a single input and output channel + var node = source.context.createScriptProcessor(4096, 1, 1); + + worker.onmessage = function(message) { + var blob = message.data; + currCallback(blob); + }; + + worker.postMessage({ + command: 'init', + config: { + sampleRate: source.context.sampleRate, + }, + }); + + /** + * Sets the silence and viz callbacks, resets the silence start time, and sets recording to true. + * @param {?onSilenceCallback} onSilence - Called when silence is detected. + * @param {?visualizerCallback} visualizer - Can be used to visualize the captured buffer. + */ + var record = function(onSilence, visualizer) { + silenceCallback = onSilence; + visualizationCallback = visualizer; + start = Date.now(); + recording = true; + }; + + /** + * Sets recording to false. + */ + var stop = function() { + recording = false; + }; + + /** + * Posts "clear" message to the worker. + */ + var clear = function() { + stop(); + worker.postMessage({ command: 'clear' }); + }; + + /** + * Sets the export callback and posts an "export" message to the worker. + * @param {onExportComplete} callback - Called when the export is complete. + * @param {sampleRate} The sample rate to use in the export. + */ + var exportWAV = function(callback, sampleRate) { + currCallback = callback; + worker.postMessage({ + command: 'export', + sampleRate: sampleRate, + }); + }; + + /** + * Checks the time domain data to see if the amplitude of the audio waveform is more than + * the silence threshold. If it is, "noise" has been detected and it resets the start time. + * If the elapsed time reaches the time threshold the silence callback is called. If there is a + * visualizationCallback it invokes the visualization callback with the time domain data. + */ + var analyse = function() { + analyser.fftSize = 2048; + var bufferLength = analyser.fftSize; + var dataArray = new Uint8Array(bufferLength); + var amplitude = silenceDetectionConfig.amplitude; + var time = silenceDetectionConfig.time; + + analyser.getByteTimeDomainData(dataArray); + + if (typeof visualizationCallback === 'function') { + visualizationCallback(dataArray, bufferLength); + } + + for (var i = 0; i < bufferLength; i++) { + // Normalize between -1 and 1. + var curr_value_time = dataArray[i] / 128 - 1.0; + if ( + curr_value_time > amplitude || + curr_value_time < -1 * amplitude + ) { + start = Date.now(); + } + } + var newtime = Date.now(); + var elapsedTime = newtime - start; + if (elapsedTime > time) { + silenceCallback(); + } + }; + + /** + * The onaudioprocess event handler of the ScriptProcessorNode interface. It is the EventHandler to be + * called for the audioprocess event that is dispatched to ScriptProcessorNode node types. + * @param {AudioProcessingEvent} audioProcessingEvent - The audio processing event. + */ + node.onaudioprocess = function(audioProcessingEvent) { + if (!recording) { + return; + } + worker.postMessage({ + command: 'record', + buffer: [audioProcessingEvent.inputBuffer.getChannelData(0)], + }); + analyse(); + }; + + var analyser = source.context.createAnalyser(); + analyser.minDecibels = -90; + analyser.maxDecibels = -10; + analyser.smoothingTimeConstant = 0.85; + + source.connect(analyser); + analyser.connect(node); + node.connect(source.context.destination); + + return { + record: record, + stop: stop, + clear: clear, + exportWAV: exportWAV, + }; + }; + + /** + * Audio recorder object. Handles setting up the audio context, + * accessing the mike, and creating the Recorder object. + */ + exports.audioRecorder = function() { + /** + * Creates an audio context and calls getUserMedia to request the mic (audio). + */ + var requestDevice = function() { + if (typeof audio_context === 'undefined') { + window.AudioContext = + window.AudioContext || window.webkitAudioContext; + audio_context = new AudioContext(); + } + + return navigator.mediaDevices + .getUserMedia({ audio: true }) + .then(function(stream) { + audio_stream = stream; + }); + }; + + var createRecorder = function(silenceDetectionConfig) { + return recorder( + audio_context.createMediaStreamSource(audio_stream), + silenceDetectionConfig + ); + }; + + var audioContext = function() { + return audio_context; + }; + + return { + requestDevice: requestDevice, + createRecorder: createRecorder, + audioContext: audioContext, + }; + }; + })(); + }, + { './worker.js': 6, webworkify: 4 }, + ], + 6: [ + function(require, module, exports) { + module.exports = function(self) { + 'use strict'; + var recLength = 0, + recBuffer = [], + recordSampleRate; + + self.addEventListener('message', function(e) { + switch (e.data.command) { + case 'init': + init(e.data.config); + break; + case 'record': + record(e.data.buffer); + break; + case 'export': + exportBuffer(e.data.sampleRate); + break; + case 'clear': + clear(); + break; + } + }); + + function init(config) { + recordSampleRate = config.sampleRate; + } + + function record(inputBuffer) { + recBuffer.push(inputBuffer[0]); + recLength += inputBuffer[0].length; + } + + function exportBuffer(exportSampleRate) { + var mergedBuffers = mergeBuffers(recBuffer, recLength); + var downsampledBuffer = downsampleBuffer( + mergedBuffers, + exportSampleRate + ); + var encodedWav = encodeWAV(downsampledBuffer); + var audioBlob = new Blob([encodedWav], { + type: 'application/octet-stream', + }); + postMessage(audioBlob); + } + + function clear() { + recLength = 0; + recBuffer = []; + } + + function downsampleBuffer(buffer, exportSampleRate) { + if (exportSampleRate === recordSampleRate) { + return buffer; + } + var sampleRateRatio = recordSampleRate / exportSampleRate; + var newLength = Math.round(buffer.length / sampleRateRatio); + var result = new Float32Array(newLength); + var offsetResult = 0; + var offsetBuffer = 0; + while (offsetResult < result.length) { + var nextOffsetBuffer = Math.round( + (offsetResult + 1) * sampleRateRatio + ); + var accum = 0, + count = 0; + for ( + var i = offsetBuffer; + i < nextOffsetBuffer && i < buffer.length; + i++ + ) { + accum += buffer[i]; + count++; + } + result[offsetResult] = accum / count; + offsetResult++; + offsetBuffer = nextOffsetBuffer; + } + return result; + } + + function mergeBuffers(bufferArray, recLength) { + var result = new Float32Array(recLength); + var offset = 0; + for (var i = 0; i < bufferArray.length; i++) { + result.set(bufferArray[i], offset); + offset += bufferArray[i].length; + } + return result; + } + + function floatTo16BitPCM(output, offset, input) { + for (var i = 0; i < input.length; i++, offset += 2) { + var s = Math.max(-1, Math.min(1, input[i])); + output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true); + } + } + + function writeString(view, offset, string) { + for (var i = 0; i < string.length; i++) { + view.setUint8(offset + i, string.charCodeAt(i)); + } + } + + function encodeWAV(samples) { + var buffer = new ArrayBuffer(44 + samples.length * 2); + var view = new DataView(buffer); + + writeString(view, 0, 'RIFF'); + view.setUint32(4, 32 + samples.length * 2, true); + writeString(view, 8, 'WAVE'); + writeString(view, 12, 'fmt '); + view.setUint32(16, 16, true); + view.setUint16(20, 1, true); + view.setUint16(22, 1, true); + view.setUint32(24, recordSampleRate, true); + view.setUint32(28, recordSampleRate * 2, true); + view.setUint16(32, 2, true); + view.setUint16(34, 16, true); + writeString(view, 36, 'data'); + view.setUint32(40, samples.length * 2, true); + floatTo16BitPCM(view, 44, samples); + + return view; + } + }; + }, + {}, + ], + }, + {}, + [3] +); diff --git a/packages/aws-amplify-vue/src/components/interactions/index.js b/packages/aws-amplify-vue/src/components/interactions/index.js index fa72078ff3d..7582cd44d36 100644 --- a/packages/aws-amplify-vue/src/components/interactions/index.js +++ b/packages/aws-amplify-vue/src/components/interactions/index.js @@ -20,5 +20,5 @@ import Chatbot from './Chatbot.vue'; Vue.component('amplify-chatbot', Chatbot); export { - Chatbot, // eslint-disable-line + Chatbot, // eslint-disable-line }; diff --git a/packages/aws-amplify-vue/src/components/storage/index.js b/packages/aws-amplify-vue/src/components/storage/index.js index 5137bfe1f9b..67dcaf486be 100644 --- a/packages/aws-amplify-vue/src/components/storage/index.js +++ b/packages/aws-amplify-vue/src/components/storage/index.js @@ -19,13 +19,8 @@ import PhotoPicker from './PhotoPicker.vue'; import S3Album from './S3Album.vue'; import S3Image from './S3Image.vue'; - Vue.component('amplify-photo-picker', PhotoPicker); Vue.component('amplify-s3-album', S3Album); Vue.component('amplify-s3-image', S3Image); -export { - PhotoPicker, - S3Album, - S3Image, -}; +export { PhotoPicker, S3Album, S3Image }; diff --git a/packages/aws-amplify-vue/src/components/xr/index.js b/packages/aws-amplify-vue/src/components/xr/index.js index 0698e9ea0f0..0c9096e0ca3 100644 --- a/packages/aws-amplify-vue/src/components/xr/index.js +++ b/packages/aws-amplify-vue/src/components/xr/index.js @@ -16,6 +16,4 @@ import SumerianScene from './SumerianScene.vue'; Vue.component('amplify-sumerian-scene', SumerianScene); -export { - SumerianScene, -}; +export { SumerianScene }; diff --git a/packages/aws-amplify-vue/src/plugins/AmplifyPlugin.js b/packages/aws-amplify-vue/src/plugins/AmplifyPlugin.js index d45812d5b32..ac103ac6537 100644 --- a/packages/aws-amplify-vue/src/plugins/AmplifyPlugin.js +++ b/packages/aws-amplify-vue/src/plugins/AmplifyPlugin.js @@ -11,32 +11,30 @@ * and limitations under the License. */ - /* This plugin is a mechanism for avoiding the importation of Amplify into Amplify-Vue, while also making Amplify available to the entire host application. */ -const requiredModules = [ - 'Auth', - 'AuthClass', - 'I18n', - 'Logger', -]; +const requiredModules = ['Auth', 'AuthClass', 'I18n', 'Logger']; const AmplifyPlugin = { - install(Vue, AmplifyModules) { - const missingModules = []; - requiredModules.forEach((r) => { - if (!Object.keys(AmplifyModules).includes(r)) { - missingModules.push(r); - } - }); - if (missingModules.length > 0) { - return new Error(`AmplifyPlugin installation method did not receive required modules: ${missingModules.join(', ')}.`); //eslint-disable-line - } + install(Vue, AmplifyModules) { + const missingModules = []; + requiredModules.forEach(r => { + if (!Object.keys(AmplifyModules).includes(r)) { + missingModules.push(r); + } + }); + if (missingModules.length > 0) { + return new Error( + `AmplifyPlugin installation method did not receive required modules: ${missingModules.join( + ', ' + )}.` + ); //eslint-disable-line + } - Vue.prototype.$Amplify = AmplifyModules; - }, + Vue.prototype.$Amplify = AmplifyModules; + }, }; export default AmplifyPlugin; //eslint-disable-line diff --git a/packages/aws-amplify-vue/src/services/getUser.js b/packages/aws-amplify-vue/src/services/getUser.js index c8e13399448..b55af894730 100644 --- a/packages/aws-amplify-vue/src/services/getUser.js +++ b/packages/aws-amplify-vue/src/services/getUser.js @@ -12,12 +12,14 @@ */ function GetUser(amplify) { - return amplify.Auth.currentAuthenticatedUser().then((user) => { - if (!user) { - return null; - } - return user; - }).catch(e => new Error(e)); + return amplify.Auth.currentAuthenticatedUser() + .then(user => { + if (!user) { + return null; + } + return user; + }) + .catch(e => new Error(e)); } export default GetUser; diff --git a/packages/aws-amplify-vue/test_setup/setup-jest.ts b/packages/aws-amplify-vue/test_setup/setup-jest.ts index d71a6f739fe..683205ce18a 100644 --- a/packages/aws-amplify-vue/test_setup/setup-jest.ts +++ b/packages/aws-amplify-vue/test_setup/setup-jest.ts @@ -1,20 +1,22 @@ -window.alert = (msg) => { console.log(msg); }; +window.alert = msg => { + console.log(msg); +}; -function noOp () { } +function noOp() {} if (typeof window.URL.createObjectURL === 'undefined') { - Object.defineProperty(window.URL, 'createObjectURL', { value: noOp}) + Object.defineProperty(window.URL, 'createObjectURL', { value: noOp }); } class Worker { - constructor(stringUrl) { - this.url = stringUrl; - this.onmessage = () => {}; - } + constructor(stringUrl) { + this.url = stringUrl; + this.onmessage = () => {}; + } - postMessage(msg) { - this.onmessage(msg); - } + postMessage(msg) { + this.onmessage(msg); + } } -window.Worker = Worker; \ No newline at end of file +window.Worker = Worker; diff --git a/packages/aws-amplify-vue/vue.config.js b/packages/aws-amplify-vue/vue.config.js index fbb0b482acc..b22617da633 100644 --- a/packages/aws-amplify-vue/vue.config.js +++ b/packages/aws-amplify-vue/vue.config.js @@ -12,15 +12,15 @@ */ module.exports = { - css: { - modules: true, - /* + css: { + modules: true, + /* ! IMPORTANT ! If css.extract is true (which it is by default), then vue cli build system will extract