Skip to content

Commit

Permalink
fix(TYP-2386): Pass hidden fields via fragment (#50)
Browse files Browse the repository at this point in the history
Pass hidden fields to typeform using both query params (legacy) and fragment (new approach)
  • Loading branch information
Matej Lednicky authored Jul 1, 2020
1 parent 4901ac5 commit 0b611b9
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 68 deletions.
34 changes: 0 additions & 34 deletions demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,3 @@ window.addEventListener('message', function (event) {
window.document.title = event.data.type
}
})

var EMBED_DOM_CLASSES = [
{
selector: '.typeform-widget',
attribute: 'data-url'
}, {
selector: '.typeform-share',
attribute: 'href'
}, {
selector: '.typeform-full',
attribute: 'src'
}
]

const addQueryStringToUrl = (url, queryString) => {
return /\?/.test(url) ? `${url}&${queryString}` : `${url}?${queryString}`
}

window.addEventListener('DOMContentLoaded', function () {
var queryString = window.location.search.substring(1)
if (queryString.length === 0) {
return
}

EMBED_DOM_CLASSES
.forEach(function (embed) {
var attribute = embed.attribute
var embeds = document.querySelectorAll(embed.selector)
embeds.forEach(function (embed) {
var embedAttr = embed.getAttribute(attribute)
embed.setAttribute(attribute, addQueryStringToUrl(embedAttr, queryString))
})
})
})
2 changes: 1 addition & 1 deletion demo/full.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
width="100%"
height="100%"
frameborder="0"
src="./form/mock.html"
src="./form/mock.html#foobar=hello"
></iframe>

<script type="text/javascript" src="embed.js"></script>
Expand Down
1 change: 1 addition & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ <h2>Embed snippet</h2>
<ul>
<li><a href="./widget-v3.html">Widget accepting form and embed library version as URL parameters</a></li>
<li><a href="./widget.html">Widget *</a></li>
<li><a href="./widget-legacy.html">Widget with legacy hidden fields *</a></li>
<li><a href="./widget-v2.html">Widget with long text</a></li>
<li><a href="./multi-widget.html">Multiple widgets</a></li>
<li><a href="./full.html">Full page *</a></li>
Expand Down
9 changes: 5 additions & 4 deletions demo/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,18 @@
<body>
<a
class="typeform-share popup"
href="./form/mock.html"
href="./form/mock.html#foobar=hello"
data-mode="popup"
data-submit-close-delay="4"
target="_blank"
>
Launch me as a popup!
</a>

<!-- uses legacy hidden field in query param -->
<a
class="typeform-share popup"
href="./form/mock.html"
href="./form/mock.html?foobar=hello"
data-mode="drawer_left"
data-submit-close-delay="4"
target="_blank"
Expand All @@ -63,7 +64,7 @@

<a
class="typeform-share popup"
href="./form/mock.html"
href="./form/mock.html#foobar=hello"
data-mode="drawer_right"
data-width="400"
data-submit-close-delay="4"
Expand All @@ -76,7 +77,7 @@

<a
class="typeform-share popover"
href="./form/mock.html"
href="./form/mock.html#foobar=hello"
data-mode="popover"
data-width="500"
data-height="600"
Expand Down
19 changes: 19 additions & 0 deletions demo/widget-legacy.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Widget example</title>
<meta charset="utf-8" />
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
<link rel="stylesheet" href="demo.css" />
</head>
<body>
<div
class="typeform-widget"
data-url="./form/mock.html?foobar=hello"
style="width:100%; height:500px;"
></div>

<script type="text/javascript" src="demo.js"></script>
<script type="text/javascript" src="embed.js"></script>
</body>
</html>
4 changes: 2 additions & 2 deletions demo/widget.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Widget example</title>
<title>Widget (legacy hidden fields) example</title>
<meta charset="utf-8" />
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
<link rel="stylesheet" href="demo.css" />
</head>
<body>
<div
class="typeform-widget"
data-url="./form/mock.html"
data-url="./form/mock.html#foobar=hello"
style="width:100%; height:500px;"
></div>

Expand Down
2 changes: 1 addition & 1 deletion e2e/spec/functional/popup.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Object.keys(popupModes).forEach(popupMode => {
openPopup(popupMode)
})

it('Passes query string parameter', () => {
it('Passes hidden field parameter', () => {
cy.get(IFRAME_SELECTOR).should('have.attr', 'src').and('match', /foobar=hello/)
})

Expand Down
67 changes: 63 additions & 4 deletions e2e/spec/functional/widget.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { open, testEmbeddedForm, openOnMobile, testEmbedFormOnMobile } from '../../cypress-utils'
import { open, testEmbeddedForm, openOnMobile, testEmbedFormOnMobile, IFRAME_SELECTOR } from '../../cypress-utils'

describe('Embed Widget in div with position:absolute on mobile', () => {
it('Loads correctly the basic embed widget', () => {
Expand All @@ -9,34 +9,93 @@ describe('Embed Widget in div with position:absolute on mobile', () => {

describe('Basic Embed Widget', () => {
describe('On Desktop', () => {
it('Loads correctly the basic embed widget', () => {
before(() => {
open('/widget.html')
})

it('Loads correctly the basic embed widget', () => {
testEmbeddedForm()
})

it('Passes hidden field parameter', () => {
cy.get(IFRAME_SELECTOR).should('have.attr', 'src').and('match', /foobar=hello/)
})
})

describe('On Mobile', () => {
it('Loads correctly the basic embed widget', () => {
before(() => {
openOnMobile('/widget.html')
})

it('Loads correctly the basic embed widget', () => {
testEmbedFormOnMobile()
})

it('Passes hidden field parameter', () => {
cy.get(IFRAME_SELECTOR).should('have.attr', 'src').and('match', /foobar=hello/)
})
})
})

describe('Basic Embed Widget with Legacy Hidden Fields', () => {
describe('On Desktop', () => {
before(() => {
open('/widget-legacy.html')
})

it('Loads correctly the basic embed widget', () => {
testEmbeddedForm()
})

it('Passes hidden field parameter', () => {
cy.get(IFRAME_SELECTOR).should('have.attr', 'src').and('match', /foobar=hello/)
})
})

describe('On Mobile', () => {
before(() => {
openOnMobile('/widget-legacy.html')
})

it('Loads correctly the basic embed widget', () => {
testEmbedFormOnMobile()
})

it('Passes hidden field parameter', () => {
cy.get(IFRAME_SELECTOR).should('have.attr', 'src').and('match', /foobar=hello/)
})
})
})

describe('Full Page Embed Widget', () => {
const iframe = '#typeform-full'

describe('On Desktop', () => {
before(() => {
open('/full.html')
})

it('Loads correctly the Full Page widget', () => {
open('/full.html')
testEmbeddedForm(iframe)
})

it('Passes hidden field parameter', () => {
cy.get(iframe).should('have.attr', 'src').and('match', /foobar=hello/)
})
})

describe('On Mobile', () => {
it('Loads correctly the Full Page widget', () => {
before(() => {
openOnMobile('/full.html')
})

it('Loads correctly the Full Page widget', () => {
testEmbeddedForm(iframe) // full page widget behaves the same as on desktop (no modal window)
})

it('Passes hidden field parameter', () => {
cy.get(iframe).should('have.attr', 'src').and('match', /foobar=hello/)
})
})
})
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"build": "./scripts/build.sh",
"serve-demo": "PORT=8080 yarn serve -S demo",
"start": "NODE_ENV=development webpack-dev-server -d --config webpack.config.js --content-base ./demo",
"test": "yarn lint && yarn test:unit && yarn test:visual && yarn test:functional",
"test": "yarn lint && yarn test:unit && yarn test:functional && yarn test:visual",
"lint": "yarn eslint ./src --ext .js --ignore-path .eslintignore --max-warnings=0",
"test:unit": "yarn jest",
"test:unit:watch": "yarn jest --watch",
Expand Down
13 changes: 4 additions & 9 deletions src/core/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,16 @@ export const broadcastMessage = (embedId, event) => {
}

export const updateQueryStringParameter = (key, value, uri) => {
const re = new RegExp(`([?&])${key}=.*?(&|$)`, 'i')
const separator = uri.indexOf('?') !== -1 ? '&' : '?'
if (uri.match(re)) {
return uri.replace(re, `$1${key}=${value}$2`)
}

return `${uri + separator + key}=${value}`
return appendParamsToUrl(uri, { [key]: value })
}

export const appendParamsToUrl = (url, params) => {
const queryParameters = []
const {
query,
origin,
pathname
pathname,
hash
} = UrlParse(url, true)
const path = pathname.replace(/\/$/, '') // remove trailing slash
const parameters = Object.assign({}, query, params)
Expand All @@ -47,7 +42,7 @@ export const appendParamsToUrl = (url, params) => {
)
})

return `${origin}${path}?${queryParameters.join('&')}`
return `${origin}${path}?${queryParameters.join('&')}${hash}`
}

export const replaceExistingKeys = (obj, replacer) => {
Expand Down
14 changes: 12 additions & 2 deletions src/core/utils/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,20 @@ jest.mock('./message-propagation')

describe('Utilities', () => {
describe('appendParamsToUrl', () => {
it('should append parameters to url correctly', () => {
fixtures.urls.forEach((fixture) => {
fixtures.urls.forEach((fixture) => {
it(`should append parameters correctly to url ${fixture.url}`, () => {
const result = utils.appendParamsToUrl(fixture.url, fixture.params)
expect(result).toEqual(fixture.expected)
})
})
})

describe('updateQueryStringParameter', () => {
fixtures.urls.forEach((fixture) => {
it(`should update parameter correctly on url ${fixture.url}`, () => {
const key = Object.keys(fixture.params)[0]
const value = Object.values(fixture.params)[0]
const result = utils.updateQueryStringParameter(key, value, fixture.url)
expect(result).toEqual(fixture.expected)
})
})
Expand Down
28 changes: 18 additions & 10 deletions test/fixtures.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,63 @@
export const urls = [{
url: 'https://admin.typeform.com/to/bXK16J',
params: { 'hola': 'mandarina' },
expected: 'https://admin.typeform.com/to/bXK16J?hola=mandarina',
expected: 'https://admin.typeform.com/to/bXK16J?hola=mandarina'
}, {
url: 'https://url.com?hola=true',
params: { 'mandarina': 'apple' },
expected: 'https://url.com?hola=true&mandarina=apple',
expected: 'https://url.com?hola=true&mandarina=apple'
}, {
url: 'https://url.com/',
params: { 'mandarina': 'apple' },
expected: 'https://url.com?mandarina=apple',
expected: 'https://url.com?mandarina=apple'
}, {
url: 'https://url.com?mandarina=true',
params: { 'mandarina': 'apple' },
expected: 'https://url.com?mandarina=apple',
expected: 'https://url.com?mandarina=apple'
}, {
url: 'https://url.com?mandarina=true#naranja=yum',
params: { 'mandarina': 'apple' },
expected: 'https://url.com?mandarina=apple#naranja=yum'
}, {
url: 'https://url.com#naranja=yum',
params: { 'mandarina': 'apple' },
expected: 'https://url.com?mandarina=apple#naranja=yum'
}]

export const userAgents = [{
name: 'Safari iOS 10 (iPhone)',
ua: 'Mozilla/5.0 (iPod touch; CPU iPhone OS 10_2_1 like Mac OS X) AppleWebKit/602.4.6 (KHTML, like Gecko) Version/10.0 Mobile/14D27 Safari/602.1',
isMobile: true,
isSafari: true,
isIOSDevice: true,
isIOSDevice: true
}, {
name: 'Chrome mobile (Nexus)',
ua: 'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19',
isMobile: true,
isSafari: false,
isIOSDevice: false,
isIOSDevice: false
}, {
name: 'Safari iOS 9 (iPad)',
ua: 'Mozilla/5.0 (iPad; CPU OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B137 Safari/601.1',
isMobile: true,
isSafari: true,
isIOSDevice: true,
isIOSDevice: true
}, {
name: 'Chrome iOS 9 (iPhone)',
ua: 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/56.0.2924.87 Mobile/13B143 Safari/601.1.46',
isMobile: true,
isSafari: true, // ?
isIOSDevice: true,
isIOSDevice: true
}, {
name: 'Edge Windows',
ua: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240',
isMobile: false,
isSafari: false,
isIOSDevice: false,
isIOSDevice: false
}, {
name: 'Safari Mac OS',
ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/7046A194A',
isMobile: false,
isSafari: true,
isIOSDevice: false,
isIOSDevice: false
}]

0 comments on commit 0b611b9

Please sign in to comment.