Skip to content

Commit

Permalink
Merge branch 'main' into update-onboarding-bracket
Browse files Browse the repository at this point in the history
  • Loading branch information
franknoirot committed Apr 11, 2024
2 parents 14e7fe2 + 15b9f43 commit 2f91746
Show file tree
Hide file tree
Showing 12 changed files with 321 additions and 244 deletions.
287 changes: 150 additions & 137 deletions e2e/playwright/flow-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import { test, expect } from '@playwright/test'
import { getUtils } from './test-utils'
import waitOn from 'wait-on'
import { roundOff } from 'lib/utils'
import { basicStorageState } from './storageStates'
import * as TOML from '@iarna/toml'
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
import { Themes } from 'lib/theme'
import { secrets } from './secrets'
import {
TEST_SETTINGS,
TEST_SETTINGS_KEY,
TEST_SETTINGS_CORRUPTED,
TEST_SETTINGS_ONBOARDING,
} from './storageStates'

/*
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
Expand All @@ -32,13 +37,25 @@ test.beforeEach(async ({ context, page }) => {
timeout: 5000,
})

await context.addInitScript(
async ({ token, settingsKey, settings }) => {
localStorage.setItem('TOKEN_PERSIST_KEY', token)
localStorage.setItem('persistCode', ``)
localStorage.setItem(settingsKey, settings)
},
{
token: secrets.token,
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({ settings: TEST_SETTINGS }),
}
)
// kill animations, speeds up tests and reduced flakiness
await page.emulateMedia({ reducedMotion: 'reduce' })
})

test.setTimeout(60000)

test('Basic sketch', async ({ page, context }) => {
test('Basic sketch', async ({ page }) => {
const u = getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio
Expand Down Expand Up @@ -308,9 +325,9 @@ test('if you write invalid kcl you get inlined errors', async ({ page }) => {
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
})

test('executes on load', async ({ page, context }) => {
test('executes on load', async ({ page }) => {
const u = getUtils(page)
await context.addInitScript(async () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const part001 = startSketchOn('-XZ')
Expand Down Expand Up @@ -340,9 +357,9 @@ test('executes on load', async ({ page, context }) => {
).toBeVisible()
})

test('re-executes', async ({ page, context }) => {
test('re-executes', async ({ page }) => {
const u = getUtils(page)
await context.addInitScript(async (token) => {
await page.addInitScript(async () => {
localStorage.setItem('persistCode', `const myVar = 5`)
})
await page.setViewportSize({ width: 1000, height: 500 })
Expand Down Expand Up @@ -512,134 +529,131 @@ test('Auto complete works', async ({ page }) => {
|> xLine(5, %) // lin`)
})

// Stored settings validation test
test.describe('Settings persistence and validation tests', () => {
// Override test setup
test('Stored settings are validated and fall back to defaults', async ({
page,
}) => {
// Override beforeEach test setup
// with corrupted settings
const storageState = structuredClone(basicStorageState)
const s = TOML.parse(storageState.origins[0].localStorage[2].value) as {
settings: SaveSettingsPayload
}
s.settings.app.theme = Themes.Dark
s.settings.app.projectDirectory = 123 as any
s.settings.modeling.defaultUnit = 'invalid' as any
s.settings.modeling.mouseControls = `() => alert('hack the planet')` as any
s.settings.projects.defaultProjectName = false as any
storageState.origins[0].localStorage[2].value = TOML.stringify(s)

test.use({ storageState })
await page.addInitScript(
async ({ settingsKey, settings }) => {
localStorage.setItem(settingsKey, settings)
},
{
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({ settings: TEST_SETTINGS_CORRUPTED }),
}
)

test('Stored settings are validated and fall back to defaults', async ({
page,
}) => {
const u = getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
await u.waitForAuthSkipAppStart()
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')

// Check the settings were reset
const storedSettings = TOML.parse(
await page.evaluate(() => localStorage.getItem('/user.toml') || '{}')
) as { settings: SaveSettingsPayload }
// Check the settings were reset
const storedSettings = TOML.parse(
await page.evaluate(
({ settingsKey }) => localStorage.getItem(settingsKey) || '{}',
{ settingsKey: TEST_SETTINGS_KEY }
)
) as { settings: SaveSettingsPayload }

expect(storedSettings.settings.app?.theme).toBe('dark')
expect(storedSettings.settings.app?.theme).toBe('dark')

// Check that the invalid settings were removed
expect(storedSettings.settings.modeling?.defaultUnit).toBe(undefined)
expect(storedSettings.settings.modeling?.mouseControls).toBe(undefined)
expect(storedSettings.settings.app?.projectDirectory).toBe(undefined)
expect(storedSettings.settings.projects?.defaultProjectName).toBe(undefined)
})
// Check that the invalid settings were removed
expect(storedSettings.settings.modeling?.defaultUnit).toBe(undefined)
expect(storedSettings.settings.modeling?.mouseControls).toBe(undefined)
expect(storedSettings.settings.app?.projectDirectory).toBe(undefined)
expect(storedSettings.settings.projects?.defaultProjectName).toBe(undefined)
})

test('Project settings can be set and override user settings', async ({
page,
}) => {
const u = getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
await u.waitForAuthSkipAppStart()
test('Project settings can be set and override user settings', async ({
page,
}) => {
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/', { waitUntil: 'domcontentloaded' })
await page
.getByRole('button', { name: 'Start Sketch' })
.waitFor({ state: 'visible' })

// Open the settings modal with the browser keyboard shortcut
await page.keyboard.press('Meta+Shift+,')
// Open the settings modal with the browser keyboard shortcut
await page.keyboard.press('Meta+Shift+,')

await expect(
page.getByRole('heading', { name: 'Settings', exact: true })
).toBeVisible()
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })
await expect(
page.getByRole('heading', { name: 'Settings', exact: true })
).toBeVisible()
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })

// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)

// Check that the user setting was not changed
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('dark')
// Check that the user setting was not changed
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('dark')

// Roll back to default "system" theme
await page
.getByText(
'themeRoll back themeRoll back to match defaultThe overall appearance of the appl'
)
.hover()
await page
.getByRole('button', {
name: 'Roll back theme ; Has tooltip: Roll back to match default',
})
.click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Roll back to default "system" theme
await page
.getByText(
'themeRoll back themeRoll back to match defaultThe overall appearance of the appl'
)
.hover()
await page
.getByRole('button', {
name: 'Roll back theme ; Has tooltip: Roll back to match default',
})
.click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')

// Check that the project setting did not change
await page.getByRole('radio', { name: 'Project' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
})
// Check that the project setting did not change
await page.getByRole('radio', { name: 'Project' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
})

// Onboarding tests
test.describe('Onboarding tests', () => {
// Override test setup
const storageState = structuredClone(basicStorageState)
const s = TOML.parse(storageState.origins[0].localStorage[2].value) as {
settings: SaveSettingsPayload
}
s.settings.app.onboardingStatus = '/export'
storageState.origins[0].localStorage[2].value = TOML.stringify(s)
test.use({ storageState })
test('Onboarding redirects and code updating', async ({ page }) => {
const u = getUtils(page)

test('Onboarding redirects and code updating', async ({ page, context }) => {
const u = getUtils(page)
// Override beforeEach test setup
await page.addInitScript(
async ({ settingsKey, settings }) => {
// Give some initial code, so we can test that it's cleared
localStorage.setItem('persistCode', 'const sigmaAllow = 15000')
localStorage.setItem(settingsKey, settings)
},
{
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({ settings: TEST_SETTINGS_ONBOARDING }),
}
)

await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
await u.waitForAuthSkipAppStart()
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
await u.waitForAuthSkipAppStart()

// Test that the redirect happened
await expect(page.url().split(':3000').slice(-1)[0]).toBe(
`/file/%2Fbrowser%2Fmain.kcl/onboarding/export`
)
// Test that the redirect happened
await expect(page.url().split(':3000').slice(-1)[0]).toBe(
`/file/%2Fbrowser%2Fmain.kcl/onboarding/export`
)

// Test that you come back to this page when you refresh
await page.reload()
await expect(page.url().split(':3000').slice(-1)[0]).toBe(
`/file/%2Fbrowser%2Fmain.kcl/onboarding/export`
)
// Test that you come back to this page when you refresh
await page.reload()
await expect(page.url().split(':3000').slice(-1)[0]).toBe(
`/file/%2Fbrowser%2Fmain.kcl/onboarding/export`
)

// Test that the onboarding pane loaded
const title = page.locator('[data-testid="onboarding-content"]')
await expect(title).toBeAttached()
// Test that the onboarding pane loaded
const title = page.locator('[data-testid="onboarding-content"]')
await expect(title).toBeAttached()

// Test that the code changes when you advance to the next step
await page.locator('[data-testid="onboarding-next"]').click()
await expect(page.locator('.cm-content')).toHaveText('')
// Test that the code changes when you advance to the next step
await page.locator('[data-testid="onboarding-next"]').click()
await expect(page.locator('.cm-content')).toHaveText('')

// Test that the code is not empty when you click on the next step
await page.locator('[data-testid="onboarding-next"]').click()
await expect(page.locator('.cm-content')).toHaveText(/.+/)
})
// Test that the code is not empty when you click on the next step
await page.locator('[data-testid="onboarding-next"]').click()
await expect(page.locator('.cm-content')).toHaveText(/.+/)
})

test('Selections work on fresh and edited sketch', async ({ page }) => {
Expand Down Expand Up @@ -851,19 +865,22 @@ test.describe('Command bar tests', () => {
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
})

// Override test setup code
const storageState = structuredClone(basicStorageState)
storageState.origins[0].localStorage[1].value = `const distance = sqrt(20)
const part001 = startSketchOn('-XZ')
|> startProfileAt([-6.95, 4.98], %)
|> line([25.1, 0.41], %)
|> line([0.73, -14.93], %)
|> line([-23.44, 0.52], %)
|> close(%)
`
test.use({ storageState })
test('Can extrude from the command bar', async ({ page }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`
const distance = sqrt(20)
const part001 = startSketchOn('-XZ')
|> startProfileAt([-6.95, 4.98], %)
|> line([25.1, 0.41], %)
|> line([0.73, -14.93], %)
|> line([-23.44, 0.52], %)
|> close(%)
`
)
})

test('Can extrude from the command bar', async ({ page, context }) => {
const u = getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
Expand Down Expand Up @@ -1055,9 +1072,9 @@ const part002 = startSketchOn('XY')
)
})

test('ProgramMemory can be serialised', async ({ page, context }) => {
test('ProgramMemory can be serialised', async ({ page }) => {
const u = getUtils(page)
await context.addInitScript(async () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const part = startSketchOn('XY')
Expand Down Expand Up @@ -1096,7 +1113,6 @@ test('ProgramMemory can be serialised', async ({ page, context }) => {

test("Various pipe expressions should and shouldn't allow edit and or extrude", async ({
page,
context,
}) => {
const u = getUtils(page)
const selectionsSnippets = {
Expand All @@ -1105,7 +1121,7 @@ test("Various pipe expressions should and shouldn't allow edit and or extrude",
extrudeAndEditAllowed: '|> startProfileAt([15.72, 4.7], %)',
editOnly: '|> startProfileAt([15.79, -14.6], %)',
}
await context.addInitScript(
await page.addInitScript(
async ({
extrudeAndEditBlocked,
extrudeAndEditBlockedInFunction,
Expand Down Expand Up @@ -1265,12 +1281,9 @@ test('Deselecting line tool should mean nothing happens on click', async ({
previousCodeContent = await page.locator('.cm-content').innerText()
})

test('Can edit segments by dragging their handles', async ({
page,
context,
}) => {
test('Can edit segments by dragging their handles', async ({ page }) => {
const u = getUtils(page)
await context.addInitScript(async () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const part001 = startSketchOn('-XZ')
Expand Down Expand Up @@ -1422,9 +1435,9 @@ test('Snap to close works (at any scale)', async ({ page }) => {
await doSnapAtDifferentScales([0, 10000, 10000], codeTemplate())
})

test('Sketch on face', async ({ page, context }) => {
test('Sketch on face', async ({ page }) => {
const u = getUtils(page)
await context.addInitScript(async () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const part001 = startSketchOn('-XZ')
Expand Down
Loading

0 comments on commit 2f91746

Please sign in to comment.