0
0
mirror of https://github.com/PostHog/posthog.git synced 2024-11-24 09:14:46 +01:00

fix: there is a fine line between optimising and breaking (#15931)

* fix: there is a fine line between optimising and breaking

* fix

* Fix

* fix
This commit is contained in:
Paul D'Ambra 2023-06-07 01:57:22 +01:00 committed by GitHub
parent 91e0d8c867
commit f3f3fa6a08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 329 additions and 265 deletions

View File

@ -18,10 +18,13 @@ jobs:
timeout-minutes: 5
if: github.repository == 'PostHog/posthog'
name: Determine need to run E2E checks
# Set job outputs to values from filter step
outputs:
shouldTriggerCypress: ${{ steps.changes.outputs.shouldTriggerCypress }}
steps:
# For pull requests it's not necessary to checkout the code
# For pull requests it's not necessary to check out the code
- uses: dorny/paths-filter@v2
id: filter
id: changes
with:
filters: |
shouldTriggerCypress:

View File

@ -0,0 +1,66 @@
import { urls } from 'scenes/urls'
import { randomString } from '../support/random'
import { decideResponse } from '../fixtures/api/decide'
import { savedInsights, createInsight } from '../productAnalytics'
// For tests related to trends please check trendsElements.js
describe('Insights', () => {
beforeEach(() => {
cy.intercept('https://app.posthog.com/decide/*', (req) =>
req.reply(
decideResponse({
hogql: true,
'data-exploration-insights': true,
})
)
)
cy.visit(urls.insightNew())
})
describe('duplicating insights', () => {
let insightName
beforeEach(() => {
cy.visit(urls.savedInsights()) // make sure turbo mode has cached this page
insightName = randomString('insight-name-')
createInsight(insightName)
})
it('can duplicate insights from the insights list view', () => {
cy.visit(urls.savedInsights())
cy.contains('.saved-insights table tr', insightName).within(() => {
cy.get('[data-attr="more-button"]').click()
})
cy.get('[data-attr="duplicate-insight-from-list-view"]').click()
cy.contains('.saved-insights table tr', `${insightName} (copy)`).should('exist')
})
it('can duplicate insights from the insights card view', () => {
cy.visit(urls.savedInsights())
cy.contains('.saved-insights .LemonSegmentedButton', 'Cards').click()
cy.contains('.CardMeta', insightName).within(() => {
cy.get('[data-attr="more-button"]').click()
})
cy.get('[data-attr="duplicate-insight-from-card-list-view"]').click()
cy.contains('.CardMeta', `${insightName} (copy)`).should('exist')
})
it('can duplicate from insight view', () => {
cy.get('.page-buttons [data-attr="more-button"]').click()
cy.get('[data-attr="duplicate-insight-from-insight-view"]').click()
cy.get('[data-attr="insight-name"]').should('contain', `${insightName} (copy)`)
savedInsights.checkInsightIsInListView(`${insightName} (copy)`)
})
it('can save insight as a copy', () => {
cy.get('[data-attr="insight-edit-button"]').click()
cy.get('[data-attr="insight-save-dropdown"]').click()
cy.get('[data-attr="insight-save-as-new-insight"]').click()
cy.get('.ant-modal-content .ant-btn-primary').click()
cy.get('[data-attr="insight-name"]').should('contain', `${insightName} (copy)`)
savedInsights.checkInsightIsInListView(`${insightName} (copy)`)
})
})
})

View File

@ -0,0 +1,187 @@
import { urls } from 'scenes/urls'
import { randomString } from '../support/random'
import { decideResponse } from '../fixtures/api/decide'
import { insight } from '../productAnalytics'
const hogQLQuery = `select event,
count()
from events
group by event,
properties.$browser,
person.properties.email
order by count() desc
limit 2`
// For tests related to trends please check trendsElements.js
describe('Insights', () => {
beforeEach(() => {
cy.intercept('https://app.posthog.com/decide/*', (req) =>
req.reply(
decideResponse({
hogql: true,
'data-exploration-insights': true,
})
)
)
cy.visit(urls.insightNew())
})
describe('navigation', () => {
it('can save and load and edit a SQL insight', () => {
insight.newInsight('SQL')
const insightName = randomString('SQL insight')
insight.editName(insightName)
insight.save()
cy.visit(urls.savedInsights())
cy.contains('.row-name a', insightName).click()
cy.get('[data-attr="hogql-query-editor"]').should('not.exist')
cy.get('tr.DataTable__row').should('have.length.gte', 2)
cy.get('[data-attr="insight-edit-button"]').click()
insight.clickTab('RETENTION')
cy.get('[data-attr="insight-save-button"]').click()
cy.get('.RetentionContainer canvas').should('exist')
cy.get('.RetentionTable__Tab').should('have.length', 66)
})
describe('opening a new insight directly', () => {
it('can open a new trends insight', () => {
insight.newInsight('TRENDS')
cy.get('.trends-insights-container canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
})
it('can open a new funnels insight', () => {
insight.newInsight('FUNNELS')
cy.get('.funnels-empty-state__title').should('exist')
})
it.skip('can open a new retention insight', () => {
insight.newInsight('RETENTION')
cy.get('.RetentionContainer canvas').should('exist')
cy.get('.RetentionTable__Tab').should('have.length', 66)
})
it('can open a new paths insight', () => {
insight.newInsight('PATHS')
cy.get('.Paths g').should('have.length.gte', 5) // not a fixed value unfortunately
})
it('can open a new stickiness insight', () => {
insight.newInsight('STICKINESS')
cy.get('.trends-insights-container canvas').should('exist')
})
it('can open a new lifecycle insight', () => {
insight.newInsight('LIFECYCLE')
cy.get('.trends-insights-container canvas').should('exist')
})
it('can open a new SQL insight', () => {
insight.newInsight('SQL')
insight.updateQueryEditorText(hogQLQuery, 'hogql-query-editor')
cy.get('[data-attr="hogql-query-editor"]').should('exist')
cy.get('tr.DataTable__row').should('have.length.gte', 2)
})
})
describe('opening a new insight after opening a new SQL insight', () => {
// TRICKY: these tests have identical assertions to the ones above, but we need to open a SQL insight first
// and then click a different tab to switch to that insight.
// this is because we had a bug where doing that would mean after starting to load the new insight,
// the SQL insight would be unexpectedly re-selected and the page would switch back to it
beforeEach(() => {
insight.newInsight('SQL')
insight.updateQueryEditorText(hogQLQuery, 'hogql-query-editor')
cy.get('[data-attr="hogql-query-editor"]').should('exist')
cy.get('tr.DataTable__row').should('have.length.gte', 2)
})
it('can open a new trends insight', () => {
insight.clickTab('TRENDS')
cy.get('.trends-insights-container canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
cy.contains('tr', 'No insight results').should('not.exist')
})
it('can open a new funnels insight', () => {
insight.clickTab('FUNNELS')
cy.get('.funnels-empty-state__title').should('exist')
})
it('can open a new retention insight', () => {
insight.clickTab('RETENTION')
cy.get('.RetentionContainer canvas').should('exist')
cy.get('.RetentionTable__Tab').should('have.length', 66)
})
it('can open a new paths insight', () => {
insight.clickTab('PATH')
cy.get('.Paths g').should('have.length.gte', 5) // not a fixed value unfortunately
})
it('can open a new stickiness insight', () => {
insight.clickTab('STICKINESS')
cy.get('.trends-insights-container canvas').should('exist')
})
it('can open a new lifecycle insight', () => {
insight.clickTab('LIFECYCLE')
cy.get('.trends-insights-container canvas').should('exist')
})
it('can open a new SQL insight', () => {
insight.clickTab('SQL')
insight.updateQueryEditorText(hogQLQuery, 'hogql-query-editor')
cy.get('[data-attr="hogql-query-editor"]').should('exist')
cy.get('tr.DataTable__row').should('have.length.gte', 2)
})
})
it('can open a new SQL insight and navigate to a different one, then back to SQL, and back again', () => {
/**
* This is here as a regression test. We had a bug where navigating to a new query based insight,
* then clicking on the trends tab, then on SQL, and again on trends would mean that the trends
* tab would be selected, but no data loaded for it 🤷
*/
insight.newInsight('SQL')
cy.get('[data-attr="hogql-query-editor"]').should('exist')
insight.updateQueryEditorText(hogQLQuery, 'hogql-query-editor')
cy.get('.DataTable tr').should('have.length.gte', 2)
insight.clickTab('TRENDS')
cy.get('.trends-insights-container canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
cy.contains('tr', 'No insight results').should('not.exist')
insight.clickTab('SQL')
cy.get('[data-attr="hogql-query-editor"]').should('exist')
insight.updateQueryEditorText(hogQLQuery, 'hogql-query-editor')
cy.get('.DataTable tr').should('have.length.gte', 2)
insight.clickTab('TRENDS')
cy.get('.trends-insights-container canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
cy.contains('tr', 'No insight results').should('not.exist')
})
it('can open event explorer as an insight', () => {
cy.clickNavMenu('events')
cy.get('[data-attr="open-json-editor-button"]').click()
cy.get('[data-attr="insight-json-tab"]').should('exist')
})
it('does not show the json tab usually', () => {
cy.clickNavMenu('savedinsights')
cy.get('[data-attr="insight-json-tab"]').should('not.exist')
})
})
})

View File

@ -0,0 +1,67 @@
import { urls } from 'scenes/urls'
import { randomString } from '../support/random'
import { decideResponse } from '../fixtures/api/decide'
import { insight } from '../productAnalytics'
// For tests related to trends please check trendsElements.js
describe('Insights', () => {
beforeEach(() => {
cy.intercept('https://app.posthog.com/decide/*', (req) =>
req.reply(
decideResponse({
hogql: true,
'data-exploration-insights': true,
})
)
)
cy.visit(urls.insightNew())
})
describe('unsaved insights confirmation', () => {
it('can move away from an unchanged new insight without confirm()', () => {
insight.newInsight()
cy.log('Navigate away')
cy.get('[data-attr="menu-item-featureflags"]').click()
cy.log('We should be on the Feature Flags page now')
cy.url().should('include', '/feature_flags')
})
it('Can navigate away from unchanged saved insight without confirm()', () => {
const insightName = randomString('to save and then navigate away from')
insight.create(insightName)
cy.get('[data-attr="menu-item-annotations"]').click()
// the annotations API call is made before the annotations page loads, so we can't wait for it
cy.get('[data-attr="annotations-content"]').should('exist')
cy.url().should('include', '/annotations')
})
it('Can keep editing changed new insight after navigating away with confirm() rejection (case 1)', () => {
cy.on('window:confirm', () => {
return false
})
insight.newInsight()
cy.log('Add series')
cy.get('[data-attr=add-action-event-button]').click()
cy.log('Navigate away')
cy.get('[data-attr="menu-item-featureflags"]').click()
cy.log('Save button should still be here because case 1 rejects confirm()')
cy.get('[data-attr="insight-save-button"]').should('exist')
})
it('Can navigate away from changed new insight with confirm() acceptance (case 2)', () => {
cy.on('window:confirm', () => {
return true
})
insight.newInsight()
cy.log('Add series')
cy.get('[data-attr=add-action-event-button]').click()
cy.log('Navigate away')
cy.get('[data-attr="menu-item-featureflags"]').click()
cy.url().should('include', '/feature_flags')
})
})
})

View File

@ -3,16 +3,8 @@ import { randomString } from '../support/random'
import { decideResponse } from '../fixtures/api/decide'
import { savedInsights, createInsight, insight } from '../productAnalytics'
const hogQLQuery = `select event,
count()
from events
group by event,
properties.$browser,
person.properties.email
order by count() desc
limit 2`
// For tests related to trends please check trendsElements.js
// insight tests were split up because Cypress was struggling with this many tests in one file🙈
describe('Insights', () => {
beforeEach(() => {
cy.intercept('https://app.posthog.com/decide/*', (req) =>
@ -97,53 +89,6 @@ describe('Insights', () => {
savedInsights.checkInsightIsInListView(insightName)
})
describe('unsaved insights confirmation', () => {
it('can move away from an unchanged new insight without confirm()', () => {
insight.newInsight()
cy.log('Navigate away')
cy.get('[data-attr="menu-item-featureflags"]').click()
cy.log('We should be on the Feature Flags page now')
cy.url().should('include', '/feature_flags')
})
it('Can navigate away from unchanged saved insight without confirm()', () => {
const insightName = randomString('to save and then navigate away from')
insight.create(insightName)
cy.get('[data-attr="menu-item-annotations"]').click()
// the annotations API call is made before the annotations page loads, so we can't wait for it
cy.get('[data-attr="annotations-content"]').should('exist')
cy.url().should('include', '/annotations')
})
it('Can keep editing changed new insight after navigating away with confirm() rejection (case 1)', () => {
cy.on('window:confirm', () => {
return false
})
insight.newInsight()
cy.log('Add series')
cy.get('[data-attr=add-action-event-button]').click()
cy.log('Navigate away')
cy.get('[data-attr="menu-item-featureflags"]').click()
cy.log('Save button should still be here because case 1 rejects confirm()')
cy.get('[data-attr="insight-save-button"]').should('exist')
})
it('Can navigate away from changed new insight with confirm() acceptance (case 2)', () => {
cy.on('window:confirm', () => {
return true
})
insight.newInsight()
cy.log('Add series')
cy.get('[data-attr=add-action-event-button]').click()
cy.log('Navigate away')
cy.get('[data-attr="menu-item-featureflags"]').click()
cy.url().should('include', '/feature_flags')
})
})
it('Shows not found error with invalid short URL', () => {
cy.visit('/i/i_dont_exist')
cy.location('pathname').should('eq', '/insights/i_dont_exist')
@ -205,210 +150,6 @@ describe('Insights', () => {
})
})
describe('duplicating insights', () => {
let insightName
beforeEach(() => {
cy.visit(urls.savedInsights()) // make sure turbo mode has cached this page
insightName = randomString('insight-name-')
createInsight(insightName)
})
it('can duplicate insights from the insights list view', () => {
cy.visit(urls.savedInsights())
cy.contains('.saved-insights table tr', insightName).within(() => {
cy.get('[data-attr="more-button"]').click()
})
cy.get('[data-attr="duplicate-insight-from-list-view"]').click()
cy.contains('.saved-insights table tr', `${insightName} (copy)`).should('exist')
})
it('can duplicate insights from the insights card view', () => {
cy.visit(urls.savedInsights())
cy.contains('.saved-insights .LemonSegmentedButton', 'Cards').click()
cy.contains('.CardMeta', insightName).within(() => {
cy.get('[data-attr="more-button"]').click()
})
cy.get('[data-attr="duplicate-insight-from-card-list-view"]').click()
cy.contains('.CardMeta', `${insightName} (copy)`).should('exist')
})
it('can duplicate from insight view', () => {
cy.get('.page-buttons [data-attr="more-button"]').click()
cy.get('[data-attr="duplicate-insight-from-insight-view"]').click()
cy.get('[data-attr="insight-name"]').should('contain', `${insightName} (copy)`)
savedInsights.checkInsightIsInListView(`${insightName} (copy)`)
})
it('can save insight as a copy', () => {
cy.get('[data-attr="insight-edit-button"]').click()
cy.get('[data-attr="insight-save-dropdown"]').click()
cy.get('[data-attr="insight-save-as-new-insight"]').click()
cy.get('.ant-modal-content .ant-btn-primary').click()
cy.get('[data-attr="insight-name"]').should('contain', `${insightName} (copy)`)
savedInsights.checkInsightIsInListView(`${insightName} (copy)`)
})
})
describe('navigation', () => {
it('can save and load and edit a SQL insight', () => {
insight.newInsight('SQL')
const insightName = randomString('SQL insight')
insight.editName(insightName)
insight.save()
cy.visit(urls.savedInsights())
cy.contains('.row-name a', insightName).click()
cy.get('[data-attr="hogql-query-editor"]').should('not.exist')
cy.get('tr.DataTable__row').should('have.length.gte', 2)
cy.get('[data-attr="insight-edit-button"]').click()
insight.clickTab('RETENTION')
cy.get('[data-attr="insight-save-button"]').click()
cy.get('.RetentionContainer canvas').should('exist')
cy.get('.RetentionTable__Tab').should('have.length', 66)
})
describe('opening a new insight directly', () => {
it('can open a new trends insight', () => {
insight.newInsight('TRENDS')
cy.get('.trends-insights-container canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
})
it('can open a new funnels insight', () => {
insight.newInsight('FUNNELS')
cy.get('.funnels-empty-state__title').should('exist')
})
it.skip('can open a new retention insight', () => {
insight.newInsight('RETENTION')
cy.get('.RetentionContainer canvas').should('exist')
cy.get('.RetentionTable__Tab').should('have.length', 66)
})
it('can open a new paths insight', () => {
insight.newInsight('PATHS')
cy.get('.Paths g').should('have.length.gte', 5) // not a fixed value unfortunately
})
it('can open a new stickiness insight', () => {
insight.newInsight('STICKINESS')
cy.get('.trends-insights-container canvas').should('exist')
})
it('can open a new lifecycle insight', () => {
insight.newInsight('LIFECYCLE')
cy.get('.trends-insights-container canvas').should('exist')
})
it('can open a new SQL insight', () => {
insight.newInsight('SQL')
insight.updateQueryEditorText(hogQLQuery, 'hogql-query-editor')
cy.get('[data-attr="hogql-query-editor"]').should('exist')
cy.get('tr.DataTable__row').should('have.length.gte', 2)
})
})
describe('opening a new insight after opening a new SQL insight', () => {
// TRICKY: these tests have identical assertions to the ones above, but we need to open a SQL insight first
// and then click a different tab to switch to that insight.
// this is because we had a bug where doing that would mean after starting to load the new insight,
// the SQL insight would be unexpectedly re-selected and the page would switch back to it
beforeEach(() => {
insight.newInsight('SQL')
insight.updateQueryEditorText(hogQLQuery, 'hogql-query-editor')
cy.get('[data-attr="hogql-query-editor"]').should('exist')
cy.get('tr.DataTable__row').should('have.length.gte', 2)
})
it('can open a new trends insight', () => {
insight.clickTab('TRENDS')
cy.get('.trends-insights-container canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
cy.contains('tr', 'No insight results').should('not.exist')
})
it('can open a new funnels insight', () => {
insight.clickTab('FUNNELS')
cy.get('.funnels-empty-state__title').should('exist')
})
it('can open a new retention insight', () => {
insight.clickTab('RETENTION')
cy.get('.RetentionContainer canvas').should('exist')
cy.get('.RetentionTable__Tab').should('have.length', 66)
})
it('can open a new paths insight', () => {
insight.clickTab('PATH')
cy.get('.Paths g').should('have.length.gte', 5) // not a fixed value unfortunately
})
it('can open a new stickiness insight', () => {
insight.clickTab('STICKINESS')
cy.get('.trends-insights-container canvas').should('exist')
})
it('can open a new lifecycle insight', () => {
insight.clickTab('LIFECYCLE')
cy.get('.trends-insights-container canvas').should('exist')
})
it('can open a new SQL insight', () => {
insight.clickTab('SQL')
insight.updateQueryEditorText(hogQLQuery, 'hogql-query-editor')
cy.get('[data-attr="hogql-query-editor"]').should('exist')
cy.get('tr.DataTable__row').should('have.length.gte', 2)
})
})
it('can open a new SQL insight and navigate to a different one, then back to SQL, and back again', () => {
/**
* This is here as a regression test. We had a bug where navigating to a new query based insight,
* then clicking on the trends tab, then on SQL, and again on trends would mean that the trends
* tab would be selected, but no data loaded for it 🤷
*/
insight.newInsight('SQL')
cy.get('[data-attr="hogql-query-editor"]').should('exist')
insight.updateQueryEditorText(hogQLQuery, 'hogql-query-editor')
cy.get('.DataTable tr').should('have.length.gte', 2)
insight.clickTab('TRENDS')
cy.get('.trends-insights-container canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
cy.contains('tr', 'No insight results').should('not.exist')
insight.clickTab('SQL')
cy.get('[data-attr="hogql-query-editor"]').should('exist')
insight.updateQueryEditorText(hogQLQuery, 'hogql-query-editor')
cy.get('.DataTable tr').should('have.length.gte', 2)
insight.clickTab('TRENDS')
cy.get('.trends-insights-container canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
cy.contains('tr', 'No insight results').should('not.exist')
})
it('can open event explorer as an insight', () => {
cy.clickNavMenu('events')
cy.get('[data-attr="open-json-editor-button"]').click()
cy.get('[data-attr="insight-json-tab"]').should('exist')
})
it('does not show the json tab usually', () => {
cy.clickNavMenu('savedinsights')
cy.get('[data-attr="insight-json-tab"]').should('not.exist')
})
})
describe('view source', () => {
it('can open the query editor', () => {
insight.newInsight('TRENDS')

View File

@ -91,8 +91,7 @@ describe('Invite Signup', () => {
cy.location('pathname').should('include', 'verify_email')
// Log out, log in as main
cy.get('[data-attr=top-menu-toggle]').click()
cy.get('[data-attr=top-menu-item-logout]').click()
cy.visit('/logout')
cy.login()
// Go to organization settings

View File

@ -49,7 +49,8 @@ describe('Signup', () => {
cy.get('[data-attr=signup-role-at-organization]').contains('Engineering')
cy.get('[data-attr=signup-submit]').click()
cy.location('pathname').should('eq', '/verify_email')
// lazy regex for a guid
cy.location('pathname').should('match', /\/verify_email\/[a-zA-Z0-9_.-]*/)
})
it('Can fill out all the fields on social login', () => {