Skip to content

Commit

Permalink
feat: dead click detection (#1463)
Browse files Browse the repository at this point in the history
Co-authored-by: Phani Raj <[email protected]>
  • Loading branch information
pauldambra and Phanatic authored Oct 31, 2024
1 parent 19fc73b commit c3de1e5
Show file tree
Hide file tree
Showing 14 changed files with 954 additions and 8 deletions.
56 changes: 55 additions & 1 deletion cypress/e2e/capture.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { version } from '../../package.json'

import { getBase64EncodedPayload, getGzipEncodedPayload, getPayload } from '../support/compression'
import { start } from '../support/setup'
import { pollPhCaptures } from '../support/assertions'

const urlWithVersion = new RegExp(`&ver=${version}`)

Expand Down Expand Up @@ -286,7 +287,9 @@ describe('Event capture', () => {
it('does not autocapture anything when /decide is disabled', () => {
start({ options: { autocapture: false, advanced_disable_decide: true }, waitForDecide: false })

cy.get('body').click(100, 100).click(98, 102).click(101, 103)
cy.get('body').click(100, 100)
cy.get('body').click(98, 102)
cy.get('body').click(101, 103)
cy.get('[data-cy-custom-event-button]').click()

// No autocapture events, still captures custom events
Expand Down Expand Up @@ -375,4 +378,55 @@ describe('Event capture', () => {
})
})
})

it('capture dead clicks when configured to', () => {
start({
options: {
capture_dead_clicks: true,
},
})

cy.get('[data-cy-not-an-order-button]').click()

pollPhCaptures('$dead_click').then(() => {
cy.phCaptures({ full: true }).then((captures) => {
const deadClicks = captures.filter((capture) => capture.event === '$dead_click')
expect(deadClicks.length).to.eq(1)
const deadClick = deadClicks[0]
expect(deadClick.properties.$dead_click_last_mutation_timestamp).to.be.a('number')
expect(deadClick.properties.$dead_click_event_timestamp).to.be.a('number')
expect(deadClick.properties.$dead_click_absolute_delay_ms).to.be.greaterThan(2500)
expect(deadClick.properties.$dead_click_scroll_timeout).to.eq(false)
expect(deadClick.properties.$dead_click_mutation_timeout).to.eq(false)
expect(deadClick.properties.$dead_click_absolute_timeout).to.eq(true)
})
})
})

it('does not capture dead click for selected text', () => {
start({
options: {
capture_dead_clicks: true,
},
})

cy.get('[data-cy-dead-click-text]').then(($el) => {
const text = $el.text()
const wordToSelect = text.split(' ')[0]
const position = text.indexOf(wordToSelect)

// click the text to make a selection
cy.get('[data-cy-dead-click-text]')
.trigger('mousedown', position, 0)
.trigger('mousemove', position + wordToSelect.length, 0)
.trigger('mouseup')
.trigger('dblclick', position, 0)
})

cy.wait(1000)
cy.phCaptures({ full: true }).then((captures) => {
const deadClicks = captures.filter((capture) => capture.event === '$dead_click')
expect(deadClicks.length).to.eq(0)
})
})
})
16 changes: 13 additions & 3 deletions cypress/e2e/surveys.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { getPayload } from '../support/compression'
import 'cypress-localstorage-commands'

function onPageLoad(options = {}) {
cy.posthog().then((ph) => {
ph.persistence?.properties().clear()
})

cy.posthogInit(options)
cy.wait('@decide')
cy.wait('@surveys')
Expand Down Expand Up @@ -335,8 +339,13 @@ describe('Surveys', () => {
onPageLoad()
cy.wait('@capture-assertion')
cy.get('.PostHogSurvey12345').shadow().find('.survey-form').should('be.visible')
cy.get('.PostHogSurvey12345').shadow().find('#surveyQuestion0Choice3').click()
cy.get('.PostHogSurvey12345').shadow().find('input[type=text]').type('Product engineer')
cy.get('.PostHogSurvey12345').shadow().find('#surveyQuestion0Choice3').and('not.be.disabled').click()
// TODO: you have to click on the input to activate it, really clicking on the parent should select the input
cy.get('.PostHogSurvey12345').shadow().find('#surveyQuestion0Choice3Open').and('not.be.disabled').click()
cy.get('.PostHogSurvey12345')
.shadow()
.find('input[type=text]#surveyQuestion0Choice3Open')
.type('Product engineer')
cy.get('.PostHogSurvey12345').shadow().find('.form-submit').click()
cy.wait('@capture-assertion').then(async ({ request }) => {
const captures = await getPayload(request)
Expand Down Expand Up @@ -590,7 +599,7 @@ describe('Surveys', () => {
cy.phCaptures().should('include', 'survey sent')
})

it('wigetType is custom selector', () => {
it('widgetType is custom selector', () => {
cy.intercept('GET', '**/surveys/*', {
surveys: [
{
Expand All @@ -615,6 +624,7 @@ describe('Surveys', () => {
onPageLoad()
cy.get('.PostHogWidget123').shadow().find('.ph-survey-widget-tab').should('not.exist')
cy.get('.test-surveys').click()
cy.wait(5000)
cy.get('.PostHogWidget123').shadow().find('.survey-form').should('be.visible')
cy.get('.PostHogWidget123').shadow().find('.survey-question').should('have.text', 'Feedback for us?')
cy.get('.PostHogWidget123')
Expand Down
1 change: 1 addition & 0 deletions cypress/support/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ beforeEach(() => {
'exception-autocapture',
'tracing-headers',
'web-vitals',
'dead-clicks-autocapture',
]
lazyLoadedJSFiles.forEach((key: string) => {
cy.readFile(`dist/${key}.js`).then((body) => {
Expand Down
6 changes: 6 additions & 0 deletions playground/cypress-full/index.html

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions playground/cypress/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@
Capture as string
</button>

<div style="display: flex; flex-direction: column; gap: 0.5em;">
<h3>my favourite takeaway has this order now not button in their hero image</h3>
<div>it's a great example of why you need dead click tracking</div>
<img data-cy-not-an-order-button width="400" height="200" alt="my favourite takeaway has this order now not button in their hero image" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAIAAADTED8xAAADMElEQVR4nOzVwQnAIBQFQYXff81RUkQCOyDj1YOPnbXWPmeTRef+/3O/OyBjzh3CD95BfqICMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMK0CMO0TAAD//2Anhf4QtqobAAAAAElFTkSuQmCC" />
</div>

<script>
!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getSurveys getActiveMatchingSurveys captureException".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
</script>
Expand Down
Loading

0 comments on commit c3de1e5

Please sign in to comment.