From 72be438092e71e53e45807574ef5978d443065b6 Mon Sep 17 00:00:00 2001 From: Max Prilutskiy Date: Wed, 6 May 2020 10:02:05 +0300 Subject: [PATCH 1/9] feat: Added onReady & onClose to the API --- .editorconfig | 2 -- .gitignore | 4 ++-- README.md | 20 +++++++++++++++++--- src/core/make-popup.js | 20 ++++++++++++++++---- src/core/make-widget.js | 3 +++ src/core/utils/get-post-message-handler.js | 11 +++++++++++ 6 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 src/core/utils/get-post-message-handler.js diff --git a/.editorconfig b/.editorconfig index 6b1aa0c8..72823be4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,5 @@ end_of_line=lf charset=utf-8 trim_trailing_whitespace=true insert_final_newline=true - -[*.js] indent_style=space indent_size=2 diff --git a/.gitignore b/.gitignore index 4600e634..94492937 100644 --- a/.gitignore +++ b/.gitignore @@ -57,5 +57,5 @@ node_modules # codeceptjs e2e/output -# cypress -cypress \ No newline at end of file +# cypress +cypress diff --git a/README.md b/README.md index 797200d0..bed0340e 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ typeformEmbed.makeWidget(element, url, options) | hideFooter | Hide typeform footer, that appears showing the progress bar and the navigation buttons. | `Boolean` | false | | hideHeaders | Hide typeform header, that appears when you have a Question group, or a long question that you need to scroll through to answer, like a Multiple Choice block. | `Boolean` | false | | onSubmit | Callback function that will be executed right after the typeform is successfully submitted. | `Function` | - | + | onReady | Callback function that will be executed once the typeform is ready. | `Function` | - | #### Example: @@ -73,6 +74,9 @@ typeformEmbed.makeWidget(element, url, options) hideScrollbars: true, onSubmit: function () { console.log('Typeform successfully submitted') + }, + onReady: function () { + console.log('Typeform is ready') } } ) @@ -99,6 +103,10 @@ typeformEmbed.makePopup(url, options) | hideHeaders | Hide typeform header, that appears when you have a Question group, or a long question that you need to scroll through to answer, like a Multiple Choice block. | `Boolean` | false | | drawerWidth | Specify the width of the drawer (only applies if using `mode` `"drawer_left"` or `"drawer_right"`). | `Number` (pixels) | 800 | | onSubmit | Callback function that will be executed right after the typeform is successfully submitted. | `Function` | - | + | onReady | Callback function that will be executed once the typeform is ready. | + `Function` | - | + | onClose | Callback function that will be executed once the typeform is closed. | + `Function` | - | #### Example: @@ -112,6 +120,12 @@ typeformEmbed.makePopup(url, options) hideScrollbars: true, onSubmit: function () { console.log('Typeform successfully submitted') + }, + onReady: function () { + console.log('Typeform is ready') + }, + onClose: function () { + console.log('Typeform is closed') } } ) @@ -140,15 +154,15 @@ Although we have no hard limit, we recommend having a height of at least 350px. We use `position: fixed` to position our modal relative to its containing block established by the viewport. If one of the modal ancestors has a `transform`, `perspective`, or `filter` css property set to something other than `none` the positioning will be relative to it and probably not visible by the user. ## Tests -In order to run visual tests, it is need an applitools key. -- Add a `.env` file in your root, you can look at the `.env.example` +In order to run visual tests, it is need an applitools key. +- Add a `.env` file in your root, you can look at the `.env.example` - Add your api key `EYES_API_KEY=HERE_GOES_YOUR_KEY` - (Optional) You can add the url, by default the url is `http://localhost:8080` - Start the server `yarn start` - Run the tests with `yarn test` - - This command will run all the tests. That means **unit tests**, **integration tests** and **visual tests** -This is the list of all the test commands, if you want to run them one by one: +This is the list of all the test commands, if you want to run them one by one: - `yarn test:unit` --> Runs unit tests - `yarn test:functional` --> Runs cross browser functional tests with Cypress - `yarn test:visual` --> Runs visual tests with CodeceptJs, WebDriver, and Applitools. diff --git a/src/core/make-popup.js b/src/core/make-popup.js index 7dd0506d..3e6a7f9c 100644 --- a/src/core/make-popup.js +++ b/src/core/make-popup.js @@ -18,6 +18,7 @@ import Popup, { DEFAULT_AUTOCLOSE_TIMEOUT } from './views/popup' import MobileModal from './views/mobile-modal' +import { getPostMessageHandler } from './utils/get-post-message-handler' const DEFAULT_DRAWER_WIDTH = 800 @@ -41,7 +42,8 @@ const queryStringKeys = { disableTracking: 'disable-tracking' } -const renderComponent = (url, domNode, options, onClose) => { +const renderComponent = (params, options) => { + const { url, domNode, close } = params const { autoClose, buttonText, @@ -59,7 +61,7 @@ const renderComponent = (url, domNode, options, onClose) => { render( , @@ -73,7 +75,7 @@ const renderComponent = (url, domNode, options, onClose) => { buttonText={buttonText} embedId={embedId} isAutoCloseEnabled={isAutoCloseEnabled} - onClose={onClose} + onClose={close} onSubmit={onSubmit} open url={urlWithQueryString} @@ -84,6 +86,9 @@ const renderComponent = (url, domNode, options, onClose) => { } export default function makePopup (url, options) { + window.addEventListener('message', getPostMessageHandler('form-ready', options.onReady)) + window.addEventListener('message', getPostMessageHandler('form-closed', options.onClose)) + const embedId = randomString() options = { @@ -109,10 +114,17 @@ export default function makePopup (url, options) { open (event) { const { currentTarget } = event || {} const currentUrl = currentTarget && currentTarget.href ? currentTarget.href : url - renderComponent(currentUrl, domNode, options, this.close) + const params = { + domNode, + url: currentUrl, + close: this.close + } + + renderComponent(params, options) }, close () { window.postMessage({ type: 'form-closed', embedId }, '*') + unmountComponentAtNode(domNode) } } diff --git a/src/core/make-widget.js b/src/core/make-widget.js index e70477e6..c56689ed 100644 --- a/src/core/make-widget.js +++ b/src/core/make-widget.js @@ -11,6 +11,7 @@ import { isMobile } from './utils/mobile-detection' import Widget from './views/widget' +import { getPostMessageHandler } from './utils/get-post-message-handler' const defaultOptions = { mode: 'embed-widget', @@ -32,6 +33,8 @@ const queryStringKeys = { export default function makeWidget (element, url, options) { options = { ...defaultOptions, ...options } + window.addEventListener('message', getPostMessageHandler('form-ready', options.onReady)) + const enabledFullscreen = isMobile(navigator.userAgent) let queryStrings = replaceExistingKeys(options, queryStringKeys) diff --git a/src/core/utils/get-post-message-handler.js b/src/core/utils/get-post-message-handler.js new file mode 100644 index 00000000..b68a0402 --- /dev/null +++ b/src/core/utils/get-post-message-handler.js @@ -0,0 +1,11 @@ +export const getPostMessageHandler = (type, handler, options = {}) => (event) => { + try { + if (event.data.type !== type) { return } + + if (options.includePayload) { + handler(event) + } else { + handler() + } + } catch (e) { } +} From b3280d5fd9ea914a7e7496720583cc1e265d3729 Mon Sep 17 00:00:00 2001 From: Max Prilutskiy Date: Wed, 6 May 2020 11:42:54 +0300 Subject: [PATCH 2/9] chore: Updated chrome version for e2e --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5014c5a4..5a53df90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ python: - "3.6" addons: - chrome: stable + chrome: "64.0" firefox: "67.0" branches: From 18f4f64d112966b456fd26a71d09e170a28ffddd Mon Sep 17 00:00:00 2001 From: Max Prilutskiy Date: Wed, 6 May 2020 11:57:47 +0300 Subject: [PATCH 3/9] chore: Chrome version changed to stable --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5a53df90..5014c5a4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ python: - "3.6" addons: - chrome: "64.0" + chrome: stable firefox: "67.0" branches: From d19a27964a0cc6fca6b529f5fd814f9f23561369 Mon Sep 17 00:00:00 2001 From: Max Prilutskiy Date: Wed, 6 May 2020 14:31:20 +0300 Subject: [PATCH 4/9] chore: Changed dist to xenial --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5014c5a4..34f5210d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ os: linux -dist: trusty +dist: xenial language: node_js @@ -10,6 +10,7 @@ python: - "3.6" addons: +# https://stackoverflow.com/questions/57903415/travis-ci-chrome-62-instead-of-77 chrome: stable firefox: "67.0" From c2f6269f85fa1c6de9423904ac9bb9e8896f60c9 Mon Sep 17 00:00:00 2001 From: Max Prilutskiy Date: Wed, 6 May 2020 15:46:49 +0300 Subject: [PATCH 5/9] chore: Refactor yarn scripts --- package.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index e284049e..bd20b457 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "README.md" ], "scripts": { - "clean": "yarn run clean:dist && yarn run clean:lib", + "clean": "yarn clean:dist && yarn clean:lib", "clean:dist": "rm -rf dist", "clean:lib": "rm -rf lib", "start": "NODE_ENV=development webpack-dev-server -d --config webpack.config.dist.js", @@ -26,24 +26,24 @@ "test:unit:watch": "jest --watch", "test:unit:coverage": "jest --coverage", "test:visual": "yarn test:visual:install && yarn test:visual:chrome && yarn test:visual:firefox && yarn test:visual:mobile", - "test:visual:install": "yarn selenium-standalone install --silent", - "test:visual:chrome": "yarn codeceptjs --config codecept-visual.conf.js run --steps --grep @desktop", - "test:visual:firefox": "yarn codeceptjs --config codecept-visual.conf.js run --steps --profile firefox --grep @desktop", - "test:visual:mobile": "yarn codeceptjs --config codecept-visual.conf.js run --steps --grep @mobile", - "test:functional:debug": "yarn cypress open", + "test:visual:install": "selenium-standalone install --silent", + "test:visual:chrome": "codeceptjs --config codecept-visual.conf.js run --steps --grep @desktop", + "test:visual:firefox": "codeceptjs --config codecept-visual.conf.js run --steps --profile firefox --grep @desktop", + "test:visual:mobile": "codeceptjs --config codecept-visual.conf.js run --steps --grep @mobile", + "test:functional:debug": "cypress open", "test:functional": "yarn test:functional:chrome && yarn test:functional:firefox", - "test:functional:firefox": "yarn cypress run --browser firefox", - "test:functional:chrome": "yarn cypress run --browser chrome", - "prepublish": "yarn run lib", + "test:functional:firefox": "cypress run --headless --browser firefox", + "test:functional:chrome": "cypress run --headless --browser chrome", + "prepublish": "yarn lib", "semantic-release": "semantic-release --branch release", "travis-deploy-once": "travis-deploy-once --pro", - "copy": "yarn run copy:assets && yarn run copy:helpcenter && yarn run copy:demo", + "copy": "yarn copy:assets && yarn copy:helpcenter && yarn copy:demo", "copy:assets": "copyfiles -f assets/* dist", "copy:helpcenter": "copyfiles -f helpcenter/* dist", "copy:demo": "copyfiles -f demo/* dist", - "build": "yarn run dist && yarn run lib && yarn run copy", - "dist": "yarn run clean:dist && webpack --config webpack.config.dist.js", - "lib": "yarn run clean:lib && webpack --config webpack.config.lib.js" + "build": "yarn dist && yarn lib && yarn copy", + "dist": "yarn clean:dist && webpack --config webpack.config.dist.js", + "lib": "yarn clean:lib && webpack --config webpack.config.lib.js" }, "devDependencies": { "@applitools/eyes-webdriverio": "^5.7.2", @@ -139,7 +139,7 @@ }, "husky": { "hooks": { - "pre-commit": "yarn run lint", + "pre-commit": "yarn lint", "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } } From 2db9754d4ef7ef04038e9a1769ca398e52b710de Mon Sep 17 00:00:00 2001 From: Max Prilutskiy Date: Wed, 6 May 2020 15:58:46 +0300 Subject: [PATCH 6/9] chore: Remove headless --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index bd20b457..f909796f 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,8 @@ "test:visual:mobile": "codeceptjs --config codecept-visual.conf.js run --steps --grep @mobile", "test:functional:debug": "cypress open", "test:functional": "yarn test:functional:chrome && yarn test:functional:firefox", - "test:functional:firefox": "cypress run --headless --browser firefox", - "test:functional:chrome": "cypress run --headless --browser chrome", + "test:functional:firefox": "cypress run --browser firefox", + "test:functional:chrome": "cypress run --browser chrome", "prepublish": "yarn lib", "semantic-release": "semantic-release --branch release", "travis-deploy-once": "travis-deploy-once --pro", From 16cb501250ac10067afb9aab006769b7c1528d97 Mon Sep 17 00:00:00 2001 From: Max Prilutskiy Date: Wed, 6 May 2020 16:30:22 +0300 Subject: [PATCH 7/9] chore: Refactoring package.json --- package.json | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index f909796f..25a2b51e 100644 --- a/package.json +++ b/package.json @@ -16,34 +16,34 @@ "README.md" ], "scripts": { - "clean": "yarn clean:dist && yarn clean:lib", + "clean": "yarn run clean:dist && yarn run clean:lib", "clean:dist": "rm -rf dist", "clean:lib": "rm -rf lib", "start": "NODE_ENV=development webpack-dev-server -d --config webpack.config.dist.js", "test": "yarn lint && yarn test:unit && yarn test:visual && yarn test:functional", - "lint": "eslint ./src --ext .js --ignore-path .eslintignore", - "test:unit": "jest", - "test:unit:watch": "jest --watch", - "test:unit:coverage": "jest --coverage", - "test:visual": "yarn test:visual:install && yarn test:visual:chrome && yarn test:visual:firefox && yarn test:visual:mobile", - "test:visual:install": "selenium-standalone install --silent", - "test:visual:chrome": "codeceptjs --config codecept-visual.conf.js run --steps --grep @desktop", - "test:visual:firefox": "codeceptjs --config codecept-visual.conf.js run --steps --profile firefox --grep @desktop", - "test:visual:mobile": "codeceptjs --config codecept-visual.conf.js run --steps --grep @mobile", - "test:functional:debug": "cypress open", - "test:functional": "yarn test:functional:chrome && yarn test:functional:firefox", - "test:functional:firefox": "cypress run --browser firefox", - "test:functional:chrome": "cypress run --browser chrome", - "prepublish": "yarn lib", - "semantic-release": "semantic-release --branch release", - "travis-deploy-once": "travis-deploy-once --pro", - "copy": "yarn copy:assets && yarn copy:helpcenter && yarn copy:demo", - "copy:assets": "copyfiles -f assets/* dist", - "copy:helpcenter": "copyfiles -f helpcenter/* dist", - "copy:demo": "copyfiles -f demo/* dist", - "build": "yarn dist && yarn lib && yarn copy", - "dist": "yarn clean:dist && webpack --config webpack.config.dist.js", - "lib": "yarn clean:lib && webpack --config webpack.config.lib.js" + "lint": "yarn eslint ./src --ext .js --ignore-path .eslintignore", + "test:unit": "yarn jest", + "test:unit:watch": "yarn jest --watch", + "test:unit:coverage": "yarn jest --coverage", + "test:visual": "yarn run test:visual:install && yarn run test:visual:chrome && yarn run test:visual:firefox && yarn run test:visual:mobile", + "test:visual:install": "yarn selenium-standalone install --silent", + "test:visual:chrome": "yarn codeceptjs --config codecept-visual.conf.js run --steps --grep @desktop", + "test:visual:firefox": "yarn codeceptjs --config codecept-visual.conf.js run --steps --profile firefox --grep @desktop", + "test:visual:mobile": "yarn codeceptjs --config codecept-visual.conf.js run --steps --grep @mobile", + "test:functional:debug": "yarn cypress open", + "test:functional": "yarn run test:functional:chrome && yarn run test:functional:firefox", + "test:functional:firefox": "yarn cypress run --browser firefox", + "test:functional:chrome": "yarn cypress run --browser chrome", + "prepublish": "yarn run lib", + "semantic-release": "yarn semantic-release --branch release", + "travis-deploy-once": "yarn travis-deploy-once --pro", + "copy": "yarn run copy:assets && yarn run copy:helpcenter && yarn run copy:demo", + "copy:assets": "yarn copyfiles -f assets/* dist", + "copy:helpcenter": "yarn copyfiles -f helpcenter/* dist", + "copy:demo": "yarn copyfiles -f demo/* dist", + "build": "yarn run dist && yarn run lib && yarn run copy", + "dist": "yarn run clean:dist && yarn webpack --config webpack.config.dist.js", + "lib": "yarn run clean:lib && yarn webpack --config webpack.config.lib.js" }, "devDependencies": { "@applitools/eyes-webdriverio": "^5.7.2", @@ -139,7 +139,7 @@ }, "husky": { "hooks": { - "pre-commit": "yarn lint", + "pre-commit": "yarn run lint", "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } } From e83af08e4723eb8cbf853732d92f6ac64de57a76 Mon Sep 17 00:00:00 2001 From: Max Prilutskiy Date: Wed, 6 May 2020 17:06:26 +0300 Subject: [PATCH 8/9] test: Units tests added --- package.json | 1 + src/core/make-popup.spec.js | 23 +++++++++++++++++++++++ src/core/make-widget.spec.js | 12 ++++++++++++ test/setup.js | 3 ++- yarn.lock | 26 ++++---------------------- 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index 25a2b51e..d044d5e1 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "jsdom": "^11.6.2", "react": "16.12.0", "react-dom": "16.12.0", + "regenerator-runtime": "^0.13.5", "selenium-standalone": "^6.17.0", "semantic-release": "^12.2.5", "travis-deploy-once": "^4.3.3", diff --git a/src/core/make-popup.spec.js b/src/core/make-popup.spec.js index 9bb2337d..6aab0651 100644 --- a/src/core/make-popup.spec.js +++ b/src/core/make-popup.spec.js @@ -104,4 +104,27 @@ describe('makePopup', () => { expect(component.type.name).toEqual('Popup') expect(component.props.options).toEqual(expect.objectContaining(options)) }) + + it(`onReady is called during initialization`, async () => { + const options = { onReady: jest.fn() } + + makePopup(URL, options) + + window.postMessage({ type: 'form-ready' }, '*') + await new Promise((resolve) => setTimeout(resolve)) + expect(options.onReady).toHaveBeenCalledTimes(1) + expect(options.onReady).toHaveBeenCalledWith() + }) + + it(`onClose is called when form closes`, async () => { + const options = { onClose: jest.fn() } + + makePopup(URL, options) + + window.postMessage({ type: 'form-closed' }, '*') + await new Promise((resolve) => setTimeout(resolve)) + + expect(options.onClose).toHaveBeenCalledTimes(1) + expect(options.onClose).toHaveBeenCalledWith() + }) }) diff --git a/src/core/make-widget.spec.js b/src/core/make-widget.spec.js index 92eec7a3..36c3ab2a 100644 --- a/src/core/make-widget.spec.js +++ b/src/core/make-widget.spec.js @@ -58,4 +58,16 @@ describe('makeWidget', () => { expect(component.type.name).toEqual('Widget') }) + + it(`onReady is called during initialization`, async () => { + const element = document.createElement('div') + const options = { onReady: jest.fn() } + + makeWidget(element, URL, options) + + window.postMessage({ type: 'form-ready' }, '*') + await new Promise((resolve) => setTimeout(resolve)) + expect(options.onReady).toHaveBeenCalledTimes(1) + expect(options.onReady).toHaveBeenCalledWith() + }) }) diff --git a/test/setup.js b/test/setup.js index 41f98f95..78faaf5a 100644 --- a/test/setup.js +++ b/test/setup.js @@ -1,3 +1,4 @@ +require('regenerator-runtime/runtime') const { JSDOM } = require('jsdom') // This setup creates a fake DOM with JSDOM and set globally @@ -8,5 +9,5 @@ const { window } = new JSDOM(' Date: Thu, 7 May 2020 12:50:21 +0300 Subject: [PATCH 9/9] Update README.md Co-authored-by: Matej Lednicky --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bed0340e..9e00ac53 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ Although we have no hard limit, we recommend having a height of at least 350px. We use `position: fixed` to position our modal relative to its containing block established by the viewport. If one of the modal ancestors has a `transform`, `perspective`, or `filter` css property set to something other than `none` the positioning will be relative to it and probably not visible by the user. ## Tests -In order to run visual tests, it is need an applitools key. +In order to run visual tests, you need an applitools key. - Add a `.env` file in your root, you can look at the `.env.example` - Add your api key `EYES_API_KEY=HERE_GOES_YOUR_KEY` - (Optional) You can add the url, by default the url is `http://localhost:8080`