Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(TYP-2386): Pass hidden fields via fragment #50

Merged
merged 1 commit into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}]