Skip to content

Commit

Permalink
chore: throw runners at e2e CI (#17492)
Browse files Browse the repository at this point in the history
* chore: throw runners at e2e CI

* add some files so we split even further

* more splitting

* more splitting
  • Loading branch information
pauldambra authored Sep 18, 2023
1 parent b7fe004 commit 1de6d5c
Show file tree
Hide file tree
Showing 11 changed files with 388 additions and 325 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:

- name: Group spec files into chunks of three
id: chunk
run: echo "chunks=$(ls cypress/e2e/* | jq --slurp --raw-input -c 'split("\n")[:-1] | _nwise(3) | join("\n")' | jq --slurp -c .)" >> $GITHUB_OUTPUT
run: echo "chunks=$(ls cypress/e2e/* | jq --slurp --raw-input -c 'split("\n")[:-1] | _nwise(2) | join("\n")' | jq --slurp -c .)" >> $GITHUB_OUTPUT

container:
name: Build and cache container image
Expand Down
54 changes: 54 additions & 0 deletions cypress/e2e/auth-password-reset.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
describe('Password Reset', () => {
beforeEach(() => {
cy.get('[data-attr=top-menu-toggle]').click()
cy.get('[data-attr=top-menu-item-logout]').click()
cy.location('pathname').should('eq', '/login')
})

it('Can request password reset', () => {
cy.get('[data-attr=login-email]').type('[email protected]').should('have.value', '[email protected]').blur()
cy.get('[data-attr=forgot-password]', { timeout: 5000 }).should('be.visible') // Wait for login precheck (note blur above)
cy.get('[data-attr="forgot-password"]').click()
cy.location('pathname').should('eq', '/reset')
cy.get('[data-attr="reset-email"]').type('[email protected]')
cy.get('button[type=submit]').click()
cy.get('div').should('contain', 'Request received successfully!')
cy.get('b').should('contain', '[email protected]')
})

it('Cannot reset with invalid token', () => {
cy.visit('/reset/user_id/token')
cy.get('div').should('contain', 'The provided link is invalid or has expired. ')
})

it('Shows validation error if passwords do not match', () => {
cy.visit('/reset/e2e_test_user/e2e_test_token')
cy.get('[data-attr="password"]').type('12345678')
cy.get('.ant-progress-bg').should('be.visible')
cy.get('[data-attr="password-confirm"]').type('1234567A')
cy.get('button[type=submit]').click()
cy.get('.text-danger').should('contain', 'Passwords do not match')
cy.location('pathname').should('eq', '/reset/e2e_test_user/e2e_test_token') // not going anywhere
})

it('Shows validation error if password is too short', () => {
cy.visit('/reset/e2e_test_user/e2e_test_token')
cy.get('[data-attr="password"]').type('123')
cy.get('[data-attr="password-confirm"]').type('123')
cy.get('button[type=submit]').click()
cy.get('.text-danger').should('be.visible')
cy.get('.text-danger').should('contain', 'must be at least 8 characters')
cy.location('pathname').should('eq', '/reset/e2e_test_user/e2e_test_token') // not going anywhere
})

it('Can reset password with valid token', () => {
cy.visit('/reset/e2e_test_user/e2e_test_token')
cy.get('[data-attr="password"]').type('NEW123456789')
cy.get('[data-attr="password-confirm"]').type('NEW123456789')
cy.get('button[type=submit]').click()
cy.get('.Toastify__toast--success').should('be.visible')

// assert the user was redirected; can't test actual redirection to /insights because the test handler doesn't actually log in the user
cy.location('pathname').should('not.contain', '/reset/e2e_test_user/e2e_test_token')
})
})
55 changes: 0 additions & 55 deletions cypress/e2e/auth.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,58 +87,3 @@ describe('Auth', () => {
cy.location('pathname').should('eq', urls.projectHomepage())
})
})

describe('Password Reset', () => {
beforeEach(() => {
cy.get('[data-attr=top-menu-toggle]').click()
cy.get('[data-attr=top-menu-item-logout]').click()
cy.location('pathname').should('eq', '/login')
})

it('Can request password reset', () => {
cy.get('[data-attr=login-email]').type('[email protected]').should('have.value', '[email protected]').blur()
cy.get('[data-attr=forgot-password]', { timeout: 5000 }).should('be.visible') // Wait for login precheck (note blur above)
cy.get('[data-attr="forgot-password"]').click()
cy.location('pathname').should('eq', '/reset')
cy.get('[data-attr="reset-email"]').type('[email protected]')
cy.get('button[type=submit]').click()
cy.get('div').should('contain', 'Request received successfully!')
cy.get('b').should('contain', '[email protected]')
})

it('Cannot reset with invalid token', () => {
cy.visit('/reset/user_id/token')
cy.get('div').should('contain', 'The provided link is invalid or has expired. ')
})

it('Shows validation error if passwords do not match', () => {
cy.visit('/reset/e2e_test_user/e2e_test_token')
cy.get('[data-attr="password"]').type('12345678')
cy.get('.ant-progress-bg').should('be.visible')
cy.get('[data-attr="password-confirm"]').type('1234567A')
cy.get('button[type=submit]').click()
cy.get('.text-danger').should('contain', 'Passwords do not match')
cy.location('pathname').should('eq', '/reset/e2e_test_user/e2e_test_token') // not going anywhere
})

it('Shows validation error if password is too short', () => {
cy.visit('/reset/e2e_test_user/e2e_test_token')
cy.get('[data-attr="password"]').type('123')
cy.get('[data-attr="password-confirm"]').type('123')
cy.get('button[type=submit]').click()
cy.get('.text-danger').should('be.visible')
cy.get('.text-danger').should('contain', 'must be at least 8 characters')
cy.location('pathname').should('eq', '/reset/e2e_test_user/e2e_test_token') // not going anywhere
})

it('Can reset password with valid token', () => {
cy.visit('/reset/e2e_test_user/e2e_test_token')
cy.get('[data-attr="password"]').type('NEW123456789')
cy.get('[data-attr="password-confirm"]').type('NEW123456789')
cy.get('button[type=submit]').click()
cy.get('.Toastify__toast--success').should('be.visible')

// assert the user was redirected; can't test actual redirection to /insights because the test handler doesn't actually log in the user
cy.location('pathname').should('not.contain', '/reset/e2e_test_user/e2e_test_token')
})
})
61 changes: 61 additions & 0 deletions cypress/e2e/dashboard-deletion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { urls } from 'scenes/urls'
import { randomString } from '../support/random'
import { dashboard, dashboards, insight, savedInsights } from '../productAnalytics'

describe('deleting dashboards', () => {
it('can delete dashboard without deleting the insights', () => {
cy.visit(urls.savedInsights()) // get insights list into turbo mode
cy.clickNavMenu('dashboards')

const dashboardName = randomString('dashboard-')
const insightName = randomString('insight-')

dashboards.createAndGoToEmptyDashboard(dashboardName)
dashboard.addInsightToEmptyDashboard(insightName)

cy.get('[data-attr="dashboard-three-dots-options-menu"]').click()
cy.get('button').contains('Delete dashboard').click()
cy.get('[data-attr="dashboard-delete-submit"]').click()

savedInsights.checkInsightIsInListView(insightName)
})

// TODO: this test works locally, just not in CI
it.skip('can delete dashboard and delete the insights', () => {
cy.visit(urls.savedInsights()) // get insights list into turbo mode
cy.clickNavMenu('dashboards')

const dashboardName = randomString('dashboard-')
const dashboardToKeepName = randomString('dashboard-to-keep')
const insightName = randomString('insight-')
const insightToKeepName = randomString('insight-to-keep-')

dashboards.createAndGoToEmptyDashboard(dashboardName)
dashboard.addInsightToEmptyDashboard(insightName)

cy.clickNavMenu('dashboards')

dashboards.createAndGoToEmptyDashboard(dashboardToKeepName)
dashboard.addInsightToEmptyDashboard(insightToKeepName)

cy.visit(urls.savedInsights())
cy.wait('@loadInsightList').then(() => {
cy.get('.saved-insights tr a').should('be.visible')

// load the named insight
cy.contains('.saved-insights tr', insightToKeepName).within(() => {
cy.get('.row-name a').click()
})

insight.addInsightToDashboard(dashboardName, { visitAfterAdding: true })

cy.get('[data-attr="dashboard-three-dots-options-menu"]').click()
cy.get('button').contains('Delete dashboard').click()
cy.contains('span.LemonCheckbox', "Delete this dashboard's insights").click()
cy.get('[data-attr="dashboard-delete-submit"]').click()

savedInsights.checkInsightIsInListView(insightToKeepName)
savedInsights.checkInsightIsNotInListView(insightName)
})
})
})
98 changes: 98 additions & 0 deletions cypress/e2e/dashboard-duplication.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { randomString } from '../support/random'
import { urls } from 'scenes/urls'
import { dashboard, dashboards, duplicateDashboardFromMenu, savedInsights } from '../productAnalytics'

describe('duplicating dashboards', () => {
let dashboardName, insightName, expectedCopiedDashboardName, expectedCopiedInsightName

beforeEach(() => {
dashboardName = randomString('dashboard-')
expectedCopiedDashboardName = `${dashboardName} (Copy)`

insightName = randomString('insight-')
expectedCopiedInsightName = `${insightName} (Copy)`

cy.visit(urls.savedInsights()) // get insights list into turbo mode
cy.clickNavMenu('dashboards')

dashboards.createAndGoToEmptyDashboard(dashboardName)
dashboard.addInsightToEmptyDashboard(insightName)

cy.contains('h4', insightName).click() // get insight into turbo mode
})

describe('from the dashboard list', () => {
it('can duplicate a dashboard without duplicating insights', () => {
cy.clickNavMenu('dashboards')
cy.get('[placeholder="Search for dashboards"]').type(dashboardName)

cy.contains('[data-attr="dashboards-table"] tr', dashboardName).within(() => {
cy.get('[data-attr="more-button"]').click()
})
duplicateDashboardFromMenu()
cy.get('h1.page-title').should('have.text', expectedCopiedDashboardName)

cy.wait('@createDashboard').then(() => {
cy.get('.CardMeta h4').should('have.text', insightName).should('not.have.text', '(Copy)')
cy.contains('h4', insightName).click()
// this works when actually using the site, but not in Cypress
// cy.get('[data-attr="save-to-dashboard-button"] .LemonBadge').should('have.text', '2')
})
})

it('can duplicate a dashboard and duplicate insights', () => {
cy.clickNavMenu('dashboards')
cy.get('[placeholder="Search for dashboards"]').type(dashboardName)

cy.contains('[data-attr="dashboards-table"] tr', dashboardName).within(() => {
cy.get('[data-attr="more-button"]').click()
})
duplicateDashboardFromMenu(true)
cy.get('h1.page-title').should('have.text', expectedCopiedDashboardName)

cy.wait('@createDashboard').then(() => {
cy.contains('h4', expectedCopiedInsightName).click()
cy.get('[data-attr="save-to-dashboard-button"] .LemonBadge').should('have.text', '1')
})

savedInsights.checkInsightIsInListView(insightName)
savedInsights.checkInsightIsInListView(expectedCopiedInsightName)
})
})

describe('from the dashboard', () => {
it('can duplicate a dashboard without duplicating insights', () => {
cy.clickNavMenu('dashboards')
dashboards.visitDashboard(dashboardName)

cy.get('[data-attr="dashboard-three-dots-options-menu"]').click()
duplicateDashboardFromMenu()
cy.get('h1.page-title').should('have.text', expectedCopiedDashboardName)

cy.wait('@createDashboard').then(() => {
cy.get('.CardMeta h4').should('have.text', insightName).should('not.have.text', '(Copy)')
cy.contains('h4', insightName).click()
// this works when actually using the site, but not in Cypress
// cy.get('[data-attr="save-to-dashboard-button"] .LemonBadge').should('have.text', '2')
})
savedInsights.checkInsightIsInListView(insightName)
savedInsights.checkInsightIsNotInListView(expectedCopiedInsightName)
})
it('can duplicate a dashboard and duplicate insights', () => {
cy.clickNavMenu('dashboards')
dashboards.visitDashboard(dashboardName)

cy.get('[data-attr="dashboard-three-dots-options-menu"]').click()
duplicateDashboardFromMenu(true)
cy.get('h1.page-title').should('have.text', expectedCopiedDashboardName)

cy.wait('@createDashboard').then(() => {
cy.contains('h4', expectedCopiedInsightName).click()
cy.get('[data-attr="save-to-dashboard-button"] .LemonBadge').should('have.text', '1')
})

savedInsights.checkInsightIsInListView(insightName)
savedInsights.checkInsightIsInListView(expectedCopiedInsightName)
})
})
})
Loading

0 comments on commit 1de6d5c

Please sign in to comment.