Continue running broken tests for Axiom metrics (#5883)

* Install Vector on Ubuntu to log failed test to Axiom

* Allow flaky tests to run on main for Axiom metrics

* Enable problematic tests on a dedicated branch
This commit is contained in:
Jace Browning
2025-03-20 16:28:08 -04:00
committed by GitHub
parent 09c6f51141
commit 2c6404f671
23 changed files with 2173 additions and 2145 deletions

View File

@ -4,7 +4,7 @@
set -euo pipefail set -euo pipefail
if [[ ! -f "test-results/.last-run.json" ]]; then if [[ ! -f "test-results/.last-run.json" ]]; then
# if no last run artifact, than run plawright normally # If no last run artifact, than run Playwright normally
echo "run playwright normally" echo "run playwright normally"
if [[ "$3" == *ubuntu* ]]; then if [[ "$3" == *ubuntu* ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:playwright:electron:ubuntu -- --shard=$1/$2 || true xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:playwright:electron:ubuntu -- --shard=$1/$2 || true
@ -13,18 +13,18 @@ if [[ ! -f "test-results/.last-run.json" ]]; then
elif [[ "$3" == *macos* ]]; then elif [[ "$3" == *macos* ]]; then
yarn test:playwright:electron:macos -- --shard=$1/$2 || true yarn test:playwright:electron:macos -- --shard=$1/$2 || true
else else
echo "Do not run playwright. Unable to detect os runtime." echo "Do not run Playwright. Unable to detect os runtime."
exit 1 exit 1
fi fi
# # send to axiom # Log failures for Axiom to pick up
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1 node playwrightProcess.mjs > /tmp/github-actions.log
fi fi
retry=1 retry=1
max_retrys=1 max_retries=1
# retry failed tests, doing our own retries because using inbuilt playwright retries causes connection issues # Retry failed tests, doing our own retries because using inbuilt Playwright retries causes connection issues
while [[ $retry -le $max_retrys ]]; do while [[ $retry -le $max_retries ]]; do
if [[ -f "test-results/.last-run.json" ]]; then if [[ -f "test-results/.last-run.json" ]]; then
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json) failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
if [[ $failed_tests -gt 0 ]]; then if [[ $failed_tests -gt 0 ]]; then
@ -40,8 +40,8 @@ while [[ $retry -le $max_retrys ]]; do
echo "Do not run playwright. Unable to detect os runtime." echo "Do not run playwright. Unable to detect os runtime."
exit 1 exit 1
fi fi
# send to axiom # Log failures for Axiom to pick up
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1 node playwrightProcess.mjs > /tmp/github-actions.log
retry=$((retry + 1)) retry=$((retry + 1))
else else
echo "retried=false" >>$GITHUB_OUTPUT echo "retried=false" >>$GITHUB_OUTPUT
@ -58,7 +58,7 @@ echo "retried=false" >>$GITHUB_OUTPUT
if [[ -f "test-results/.last-run.json" ]]; then if [[ -f "test-results/.last-run.json" ]]; then
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json) failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
if [[ $failed_tests -gt 0 ]]; then if [[ $failed_tests -gt 0 ]]; then
# if it still fails after 3 retrys, then fail the job # If it still fails after 3 retries, then fail the job
exit 1 exit 1
fi fi
fi fi

View File

@ -340,14 +340,22 @@ jobs:
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
run: yarn tronb:vite:dev run: yarn tronb:vite:dev
- name: Install good sed - name: Install vector
if: startsWith(matrix.os, 'macos') if: contains(matrix.os, 'ubuntu')
shell: bash shell: bash
run: | run: |
brew install gnu-sed curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
echo "/opt/homebrew/opt/gnu-sed/libexec/gnubin" >> $GITHUB_PATH chmod +x /tmp/vector.sh
/tmp/vector.sh -y -no-modify-path
# TODO: Add back axiom logs mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i "s#GH_ACTIONS_AXIOM_TOKEN#${{secrets.GH_ACTIONS_AXIOM_TOKEN}}#g" /tmp/vector.toml
cat /tmp/vector.toml
${HOME}/.vector/bin/vector --config /tmp/vector.toml &
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }} if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}

View File

@ -153,7 +153,8 @@ async function doBasicSketch(
} }
test.describe('Basic sketch', { tag: ['@skipWin'] }, () => { test.describe('Basic sketch', { tag: ['@skipWin'] }, () => {
test.fixme('code pane open at start', async ({ page, homePage }) => { test('code pane open at start', async ({ page, homePage }) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
await doBasicSketch(page, homePage, ['code']) await doBasicSketch(page, homePage, ['code'])
}) })

View File

@ -46,11 +46,12 @@ test.describe('Code pane and errors', { tag: ['@skipWin'] }, () => {
await expect(codePaneButtonHolder).toContainText('notification') await expect(codePaneButtonHolder).toContainText('notification')
}) })
test.skip('Opening and closing the code pane will consistently show error diagnostics', async ({ test('Opening and closing the code pane will consistently show error diagnostics', async ({
page, page,
homePage, homePage,
editor, editor,
}) => { }) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const u = await getUtils(page) const u = await getUtils(page)
// Load the app with the working starter code // Load the app with the working starter code
@ -119,9 +120,12 @@ test.describe('Code pane and errors', { tag: ['@skipWin'] }, () => {
await expect(page.locator('.cm-tooltip').first()).toBeVisible() await expect(page.locator('.cm-tooltip').first()).toBeVisible()
}) })
test.fixme( test('When error is not in view you can click the badge to scroll to it', async ({
'When error is not in view you can click the badge to scroll to it', page,
async ({ page, homePage, context }) => { homePage,
context,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
// Load the app with the working starter code // Load the app with the working starter code
await context.addInitScript((code) => { await context.addInitScript((code) => {
localStorage.setItem('persistCode', code) localStorage.setItem('persistCode', code)
@ -156,8 +160,7 @@ test.describe('Code pane and errors', { tag: ['@skipWin'] }, () => {
) )
.first() .first()
).toBeVisible() ).toBeVisible()
} })
)
test('When error is not in view WITH LINTS you can click the badge to scroll to it', async ({ test('When error is not in view WITH LINTS you can click the badge to scroll to it', async ({
context, context,

View File

@ -47,7 +47,8 @@ test.describe('Command bar tests', { tag: ['@skipWin'] }, () => {
}) })
// TODO: fix this test after the electron migration // TODO: fix this test after the electron migration
test.fixme('Fillet from command bar', async ({ page, homePage }) => { test('Fillet from command bar', async ({ page, homePage }) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',

View File

@ -635,9 +635,11 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
}) })
test.fixme( test('error with 2 source ranges gets 2 diagnostics', async ({
'error with 2 source ranges gets 2 diagnostics', page,
async ({ page, homePage }) => { homePage,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
@ -702,8 +704,7 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
// Make sure there are two diagnostics // Make sure there are two diagnostics
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(2) await expect(page.locator('.cm-lint-marker-error')).toHaveCount(2)
} })
)
test('if your kcl gets an error from the engine it is inlined', async ({ test('if your kcl gets an error from the engine it is inlined', async ({
context, context,
page, page,
@ -1121,10 +1122,11 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
} }
) )
test.fixme( test(
`Can use the import stdlib function on a local OBJ file`, `Can use the import stdlib function on a local OBJ file`,
{ tag: '@electron' }, { tag: '@electron' },
async ({ page, context }, testInfo) => { async ({ page, context }, testInfo) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const bracketDir = join(dir, 'cube') const bracketDir = join(dir, 'cube')
await fsp.mkdir(bracketDir, { recursive: true }) await fsp.mkdir(bracketDir, { recursive: true })

View File

@ -266,12 +266,13 @@ test.describe('when using the file tree to', () => {
} }
) )
test.fixme( test(
'loading small file, then large, then back to small', 'loading small file, then large, then back to small',
{ {
tag: '@electron', tag: '@electron',
}, },
async ({ page }, testInfo) => { async ({ page }, testInfo) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const { const {
panesOpen, panesOpen,
pasteCodeInEditor, pasteCodeInEditor,

View File

@ -319,9 +319,13 @@ test.describe('Onboarding tests', () => {
// (lee) The two avatar tests are weird because even on main, we don't have // (lee) The two avatar tests are weird because even on main, we don't have
// anything to do with the avatar inside the onboarding test. Due to the // anything to do with the avatar inside the onboarding test. Due to the
// low impact of an avatar not showing I'm changing this to fixme. // low impact of an avatar not showing I'm changing this to fixme.
test.fixme( test('Avatar text updates depending on image load success', async ({
'Avatar text updates depending on image load success', context,
async ({ context, page, homePage, tronApp }) => { page,
homePage,
tronApp,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
if (!tronApp) { if (!tronApp) {
fail() fail()
} }
@ -349,9 +353,7 @@ test.describe('Onboarding tests', () => {
await homePage.goToModelingScene() await homePage.goToModelingScene()
// Test that the text in this step is correct // Test that the text in this step is correct
const avatarLocator = page const avatarLocator = page.getByTestId('user-sidebar-toggle').locator('img')
.getByTestId('user-sidebar-toggle')
.locator('img')
const onboardingOverlayLocator = page const onboardingOverlayLocator = page
.getByTestId('onboarding-content') .getByTestId('onboarding-content')
.locator('div') .locator('div')
@ -374,16 +376,13 @@ test.describe('Onboarding tests', () => {
}) })
// 404 the CI avatar image // 404 the CI avatar image
await page.route( await page.route('https://lh3.googleusercontent.com/**', async (route) => {
'https://lh3.googleusercontent.com/**',
async (route) => {
await route.fulfill({ await route.fulfill({
status: 404, status: 404,
contentType: 'text/plain', contentType: 'text/plain',
body: 'Not Found!', body: 'Not Found!',
}) })
} })
)
await page.reload({ waitUntil: 'domcontentloaded' }) await page.reload({ waitUntil: 'domcontentloaded' })
@ -391,12 +390,15 @@ test.describe('Onboarding tests', () => {
await expect(avatarLocator).not.toBeVisible() await expect(avatarLocator).not.toBeVisible()
await expect(onboardingOverlayLocator).toBeVisible() await expect(onboardingOverlayLocator).toBeVisible()
await expect(onboardingOverlayLocator).toContainText('the menu button') await expect(onboardingOverlayLocator).toContainText('the menu button')
} })
)
test.fixme( test("Avatar text doesn't mention avatar when no avatar", async ({
"Avatar text doesn't mention avatar when no avatar", context,
async ({ context, page, homePage, tronApp }) => { page,
homePage,
tronApp,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
if (!tronApp) { if (!tronApp) {
fail() fail()
} }
@ -447,13 +449,15 @@ test.describe('Onboarding tests', () => {
for (const feature of userMenuFeatures) { for (const feature of userMenuFeatures) {
await expect(onboardingOverlayLocator).toContainText(feature) await expect(onboardingOverlayLocator).toContainText(feature)
} }
} })
)
}) })
test.fixme( test('Restarting onboarding on desktop takes one attempt', async ({
'Restarting onboarding on desktop takes one attempt', context,
async ({ context, page, tronApp }) => { page,
tronApp,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
if (!tronApp) { if (!tronApp) {
fail() fail()
} }
@ -551,5 +555,4 @@ test.fixme(
await expect(tutorialProjectIndicator).toBeVisible() await expect(tutorialProjectIndicator).toBeVisible()
await expect(tutorialModalText).toBeVisible() await expect(tutorialModalText).toBeVisible()
}) })
} })
)

View File

@ -850,9 +850,13 @@ openSketch = startSketchOn('XY')
}) })
}) })
test.fixme( test(`Shift-click to select and deselect sketch segments`, async ({
`Shift-click to select and deselect sketch segments`, page,
async ({ page, homePage, scene, editor }) => { homePage,
scene,
editor,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
// Locators // Locators
const firstPointLocation = { x: 200, y: 100 } const firstPointLocation = { x: 200, y: 100 }
const secondPointLocation = { x: 800, y: 100 } const secondPointLocation = { x: 800, y: 100 }
@ -999,8 +1003,7 @@ openSketch = startSketchOn('XY')
) )
}) })
}) })
} })
)
test(`Offset plane point-and-click`, async ({ test(`Offset plane point-and-click`, async ({
context, context,

View File

@ -1244,10 +1244,11 @@ test(
} }
) )
test.fixme( test(
'Deleting projects, can delete individual project, can still create projects after deleting all', 'Deleting projects, can delete individual project, can still create projects after deleting all',
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, page }, testInfo) => { async ({ context, page }, testInfo) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const projectData = [ const projectData = [
['router-template-slate', 'cylinder.kcl'], ['router-template-slate', 'cylinder.kcl'],
['bracket', 'focusrite_scarlett_mounting_braket.kcl'], ['bracket', 'focusrite_scarlett_mounting_braket.kcl'],
@ -1466,10 +1467,11 @@ test(
} }
) )
test.fixme( test(
'When the project folder is empty, user can create new project and open it.', 'When the project folder is empty, user can create new project and open it.',
{ tag: '@electron' }, { tag: '@electron' },
async ({ page }, testInfo) => { async ({ page }, testInfo) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const u = await getUtils(page) const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
@ -2050,10 +2052,11 @@ test(
) )
// Flaky // Flaky
test.fixme( test(
'Original project name persist after onboarding', 'Original project name persist after onboarding',
{ tag: '@electron' }, { tag: '@electron' },
async ({ page }, testInfo) => { async ({ page }, testInfo) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
const getAllProjects = () => page.getByTestId('project-link').all() const getAllProjects = () => page.getByTestId('project-link').all()

View File

@ -196,9 +196,15 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
}) })
}) })
test.fixme( test(`manual code selection rename`, async ({
`manual code selection rename`, context,
async ({ context, homePage, cmdBar, editor, page, scene }) => { homePage,
cmdBar,
editor,
page,
scene,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const body1CapCoords = { x: 571, y: 311 } const body1CapCoords = { x: 571, y: 311 }
await context.addInitScript((file) => { await context.addInitScript((file) => {
@ -248,8 +254,7 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
await acceptBtn.click() await acceptBtn.click()
await expect(successToast).not.toBeVisible() await expect(successToast).not.toBeVisible()
}) })
} })
)
test('multiple body selections', async ({ test('multiple body selections', async ({
context, context,

View File

@ -483,10 +483,11 @@ extrude001 = extrude(sketch001, length = 50)
} }
) )
test.fixme( test(
`Network health indicator only appears in modeling view`, `Network health indicator only appears in modeling view`,
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, page }, testInfo) => { async ({ context, page }, testInfo) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, 'bracket') const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true }) await fsp.mkdir(bracketDir, { recursive: true })

View File

@ -188,7 +188,8 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).toBeVisible() ).toBeVisible()
}) })
test.fixme('Can edit segments by dragging their handles', () => { test('Can edit segments by dragging their handles', () => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const doEditSegmentsByDraggingHandle = async ( const doEditSegmentsByDraggingHandle = async (
page: Page, page: Page,
homePage: HomePageFixture, homePage: HomePageFixture,
@ -1086,9 +1087,11 @@ profile001 = startProfileAt([${roundOff(scale * 69.6)}, ${roundOff(
) )
}) })
// TODO: fix after electron migration is merged // TODO: fix after electron migration is merged
test.fixme( test('empty-scene default-planes act as expected', async ({
'empty-scene default-planes act as expected', page,
async ({ page, homePage }) => { homePage,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
/** /**
* Tests the following things * Tests the following things
* 1) The the planes are there on load because the scene is empty * 1) The the planes are there on load because the scene is empty
@ -1185,8 +1188,7 @@ profile001 = startProfileAt([${roundOff(scale * 69.6)}, ${roundOff(
expect( expect(
await u.getGreatestPixDiff(XYPlanePoint, noPlanesColor) await u.getGreatestPixDiff(XYPlanePoint, noPlanesColor)
).toBeLessThan(3) ).toBeLessThan(3)
} })
)
test('Can attempt to sketch on revolved face', async ({ page, homePage }) => { test('Can attempt to sketch on revolved face', async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
@ -1460,10 +1462,11 @@ test.describe(`Sketching with offset planes`, () => {
}) })
test.describe('multi-profile sketching', () => { test.describe('multi-profile sketching', () => {
test.fixme( test(
`test it removes half-finished expressions when changing tools in sketch mode`, `test it removes half-finished expressions when changing tools in sketch mode`,
{ tag: ['@skipWin'] }, { tag: ['@skipWin'] },
async ({ context, page, scene, toolbar, editor, homePage, cmdBar }) => { async ({ context, page, scene, toolbar, editor, homePage, cmdBar }) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
// We seed the scene with a single offset plane // We seed the scene with a single offset plane
await context.addInitScript(() => { await context.addInitScript(() => {
localStorage.setItem( localStorage.setItem(
@ -2852,9 +2855,14 @@ loft([profile001, profile002])
) )
} }
) )
test.fixme( test('Can enter sketch loft edges offsetPlane and continue sketch', async ({
'Can enter sketch loft edges offsetPlane and continue sketch', scene,
async ({ scene, toolbar, editor, page, homePage }) => { toolbar,
editor,
page,
homePage,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
@ -2917,8 +2925,7 @@ loft([profile001, profile002])
`angledLine([0, 106.42], %, $rectangleSegmentA001)` `angledLine([0, 106.42], %, $rectangleSegmentA001)`
) )
await page.waitForTimeout(100) await page.waitForTimeout(100)
} })
)
}) })
// Regression test for https://github.com/KittyCAD/modeling-app/issues/4891 // Regression test for https://github.com/KittyCAD/modeling-app/issues/4891

View File

@ -36,10 +36,11 @@ test.setTimeout(60_000)
// a snapshot of it feels weird. I'd rather our regular tests fail. // a snapshot of it feels weird. I'd rather our regular tests fail.
// The primary failure is doExport now relies on the filesystem. We can follow // The primary failure is doExport now relies on the filesystem. We can follow
// up with another PR if we want this back. // up with another PR if we want this back.
test.skip( test(
'exports of each format should work', 'exports of each format should work',
{ tag: ['@snapshot', '@skipWin', '@skipMacos'] }, { tag: ['@snapshot', '@skipWin', '@skipMacos'] },
async ({ page, context, scene, cmdBar, tronApp }) => { async ({ page, context, scene, cmdBar, tronApp }) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
if (!tronApp) { if (!tronApp) {
fail() fail()
} }
@ -406,9 +407,6 @@ test(
'Draft segments should look right', 'Draft segments should look right',
{ tag: '@snapshot' }, { tag: '@snapshot' },
async ({ page, scene, toolbar }) => { async ({ page, scene, toolbar }) => {
// FIXME: Skip on macos its being weird.
// test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio const PUR = 400 / 37.5 //pixeltoUnitRatio
@ -585,9 +583,6 @@ test(
'Draft circle should look right', 'Draft circle should look right',
{ tag: '@snapshot' }, { tag: '@snapshot' },
async ({ page, context, cmdBar, scene }) => { async ({ page, context, cmdBar, scene }) => {
// FIXME: Skip on macos its being weird.
// test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio const PUR = 400 / 37.5 //pixeltoUnitRatio
@ -952,9 +947,6 @@ test(
) )
test.describe('Grid visibility', { tag: '@snapshot' }, () => { test.describe('Grid visibility', { tag: '@snapshot' }, () => {
// FIXME: Skip on macos its being weird.
// test.skip(process.platform === 'darwin', 'Skip on macos')
test('Grid turned off to on via command bar', async ({ test('Grid turned off to on via command bar', async ({
page, page,
cmdBar, cmdBar,
@ -1097,7 +1089,8 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
}) })
}) })
test.fixme('theme persists', async ({ page, context }) => { test('theme persists', async ({ page, context }) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const u = await getUtils(page) const u = await getUtils(page)
await context.addInitScript(async () => { await context.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(

View File

@ -3,11 +3,12 @@ import { commonPoints, getUtils } from './test-utils'
import { EngineCommand } from 'lang/std/artifactGraph' import { EngineCommand } from 'lang/std/artifactGraph'
import { uuidv4 } from 'lib/utils' import { uuidv4 } from 'lib/utils'
test.fixme('Test network and connection issues', () => { test.describe('Test network and connection issues', () => {
test( test(
'simulate network down and network little widget', 'simulate network down and network little widget',
{ tag: '@skipLocalEngine' }, { tag: '@skipLocalEngine' },
async ({ page, homePage }) => { async ({ page, homePage }) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const u = await getUtils(page) const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
@ -84,6 +85,7 @@ test.fixme('Test network and connection issues', () => {
'Engine disconnect & reconnect in sketch mode', 'Engine disconnect & reconnect in sketch mode',
{ tag: '@skipLocalEngine' }, { tag: '@skipLocalEngine' },
async ({ page, homePage, toolbar }) => { async ({ page, homePage, toolbar }) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const networkToggle = page.getByTestId('network-toggle') const networkToggle = page.getByTestId('network-toggle')
const u = await getUtils(page) const u = await getUtils(page)

View File

@ -179,9 +179,11 @@ test.describe('Testing Camera Movement', { tag: ['@skipWin'] }, () => {
}) })
// TODO: fix after electron migration is merged // TODO: fix after electron migration is merged
test.fixme( test('Zoom should be consistent when exiting or entering sketches', async ({
'Zoom should be consistent when exiting or entering sketches', page,
async ({ page, homePage }) => { homePage,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
// start new sketch pan and zoom before exiting, when exiting the sketch should stay in the same place // start new sketch pan and zoom before exiting, when exiting the sketch should stay in the same place
// than zoom and pan outside of sketch mode and enter again and it should not change from where it is // than zoom and pan outside of sketch mode and enter again and it should not change from where it is
// than again for sketching // than again for sketching
@ -340,8 +342,7 @@ test.describe('Testing Camera Movement', { tag: ['@skipWin'] }, () => {
await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ await expect(page.getByTestId('hover-highlight').first()).toBeVisible({
timeout: 10_000, timeout: 10_000,
}) })
} })
)
test(`Zoom by scroll should not fire while orbiting`, async ({ test(`Zoom by scroll should not fire while orbiting`, async ({
homePage, homePage,

View File

@ -1005,9 +1005,11 @@ part002 = startSketchOn('XZ')
} }
}) })
test.fixme( test('Horizontally constrained line remains selected after applying constraint', async ({
'Horizontally constrained line remains selected after applying constraint', page,
async ({ page, homePage }) => { homePage,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
test.setTimeout(70_000) test.setTimeout(70_000)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
@ -1025,9 +1027,9 @@ part002 = startSketchOn('XZ')
await u.waitForPageLoad() await u.waitForPageLoad()
await page.getByText('line(end = [3.79, 2.68], tag = $seg01)').click() await page.getByText('line(end = [3.79, 2.68], tag = $seg01)').click()
await expect( await expect(page.getByRole('button', { name: 'Edit Sketch' })).toBeEnabled(
page.getByRole('button', { name: 'Edit Sketch' }) { timeout: 10_000 }
).toBeEnabled({ timeout: 10_000 }) )
await page.getByRole('button', { name: 'Edit Sketch' }).click() await page.getByRole('button', { name: 'Edit Sketch' }).click()
// Wait for overlays to populate // Wait for overlays to populate
@ -1054,9 +1056,7 @@ part002 = startSketchOn('XZ')
}) })
.click() .click()
await page.waitForTimeout(500) await page.waitForTimeout(500)
await page await page.getByRole('button', { name: 'Horizontal', exact: true }).click()
.getByRole('button', { name: 'Horizontal', exact: true })
.click()
await page.waitForTimeout(500) await page.waitForTimeout(500)
await pollEditorLinesSelectedLength(page, 1) await pollEditorLinesSelectedLength(page, 1)
@ -1081,9 +1081,7 @@ part002 = startSketchOn('XZ')
await page.mouse.click(linebb.x, linebb.y) await page.mouse.click(linebb.x, linebb.y)
await expect await expect
.poll( .poll(async () => await u.getGreatestPixDiff(lineAfter, TEST_COLORS.BLUE))
async () => await u.getGreatestPixDiff(lineAfter, TEST_COLORS.BLUE)
)
.toBeLessThan(3) .toBeLessThan(3)
await page.waitForTimeout(500) await page.waitForTimeout(500)
@ -1093,10 +1091,7 @@ part002 = startSketchOn('XZ')
// await page.getByRole('button', { name: 'length', exact: true }).click() // await page.getByRole('button', { name: 'length', exact: true }).click()
await page.getByTestId('constraint-length').click() await page.getByTestId('constraint-length').click()
await page await page.getByTestId('cmd-bar-arg-value').getByRole('textbox').fill('10')
.getByTestId('cmd-bar-arg-value')
.getByRole('textbox')
.fill('10')
await page await page
.getByRole('button', { .getByRole('button', {
name: 'arrow right Continue', name: 'arrow right Continue',
@ -1111,8 +1106,7 @@ part002 = startSketchOn('XZ')
// checking the count of the overlays is a good proxy check that the client sketch scene is in a good state // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state
await expect(page.getByTestId('segment-overlay')).toHaveCount(2) await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
} })
)
}) })
test.describe('Electron constraint tests', () => { test.describe('Electron constraint tests', () => {
test( test(

View File

@ -2,7 +2,8 @@ import { test, expect } from './zoo-test'
import { getUtils } from './test-utils' import { getUtils } from './test-utils'
test.describe('Test toggling perspective', () => { test.describe('Test toggling perspective', () => {
test.fixme('via command palette and toggle', async ({ page, homePage }) => { test('via command palette and toggle', async ({ page, homePage }) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const u = await getUtils(page) const u = await getUtils(page)
// Locators and constants // Locators and constants

View File

@ -7,11 +7,9 @@ import { uuidv4 } from 'lib/utils'
import { EditorFixture } from './fixtures/editorFixture' import { EditorFixture } from './fixtures/editorFixture'
test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => { test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
test.fixme( test('Hover over a segment should show its overlay, hovering over the input overlays should show its popover, clicking the input overlay should constrain/unconstrain it:\nfor the following segments', () => {
'Hover over a segment should show its overlay, hovering over the input overlays should show its popover, clicking the input overlay should constrain/unconstrain it:\nfor the following segments',
() => {
// TODO: fix this test on mac after the electron migration // TODO: fix this test on mac after the electron migration
test.skip(process.platform === 'darwin', 'Skip on mac') test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
/** /**
* Clicks on an constrained element * Clicks on an constrained element
* @param {Page} page - The page to perform the action on * @param {Page} page - The page to perform the action on
@ -368,9 +366,12 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
}) })
// Broken on main at time of writing! // Broken on main at time of writing!
test.fixme( test('for segments [yLineTo, xLine]', async ({
'for segments [yLineTo, xLine]', page,
async ({ page, editor, homePage }) => { editor,
homePage,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
@ -444,8 +445,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
ang: ang + 180, ang: ang + 180,
locator: '[data-overlay-toolbar-index="5"]', locator: '[data-overlay-toolbar-index="5"]',
}) })
} })
)
test('for segments [yLine, angledLineOfXLength, angledLineOfYLength]', async ({ test('for segments [yLine, angledLineOfXLength, angledLineOfYLength]', async ({
page, page,
editor, editor,
@ -557,8 +557,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
'angledLineOfYLength({ angle = -91, length = 19 + 0 }, %)', 'angledLineOfYLength({ angle = -91, length = 19 + 0 }, %)',
expectAfterUnconstrained: expectAfterUnconstrained:
'angledLineOfYLength({ angle = angle002, length = 19 + 0 }, %)', 'angledLineOfYLength({ angle = angle002, length = 19 + 0 }, %)',
expectFinal: expectFinal: 'angledLineOfYLength({ angle = -91, length = 19 + 0 }, %)',
'angledLineOfYLength({ angle = -91, length = 19 + 0 }, %)',
ang: ang + 180, ang: ang + 180,
steps: 6, steps: 6,
locator: '[data-overlay-toolbar-index="8"]', locator: '[data-overlay-toolbar-index="8"]',
@ -657,9 +656,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
locator: '[data-overlay-toolbar-index="9"]', locator: '[data-overlay-toolbar-index="9"]',
}) })
const angledLineToY = await u.getBoundingBox( const angledLineToY = await u.getBoundingBox('[data-overlay-index="10"]')
'[data-overlay-index="10"]'
)
ang = await u.getAngle('[data-overlay-index="10"]') ang = await u.getAngle('[data-overlay-index="10"]')
console.log('angledLineToY') console.log('angledLineToY')
await clickUnconstrained({ await clickUnconstrained({
@ -680,8 +677,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
constraintType: 'yAbsolute', constraintType: 'yAbsolute',
expectBeforeUnconstrained: expectBeforeUnconstrained:
'angledLineToY({ angle = 89, to = 9.14 + 0 }, %)', 'angledLineToY({ angle = 89, to = 9.14 + 0 }, %)',
expectAfterUnconstrained: expectAfterUnconstrained: 'angledLineToY({ angle = 89, to = 9.14 }, %)',
'angledLineToY({ angle = 89, to = 9.14 }, %)',
expectFinal: 'angledLineToY({ angle = 89, to = yAbs001 }, %)', expectFinal: 'angledLineToY({ angle = 89, to = yAbs001 }, %)',
ang: ang + 180, ang: ang + 180,
locator: '[data-overlay-toolbar-index="10"]', locator: '[data-overlay-toolbar-index="10"]',
@ -1000,8 +996,7 @@ profile001 = startProfileAt([56.37, 120.33], sketch001)
await clickUnconstrained({ await clickUnconstrained({
hoverPos, hoverPos,
constraintType: 'yAbsolute', constraintType: 'yAbsolute',
expectBeforeUnconstrained: expectBeforeUnconstrained: 'circle(center = [xAbs001, 0], radius = 8)',
'circle(center = [xAbs001, 0], radius = 8)',
expectAfterUnconstrained: expectAfterUnconstrained:
'circle(center = [xAbs001, yAbs001], radius = 8)', 'circle(center = [xAbs001, yAbs001], radius = 8)',
expectFinal: 'circle(center = [xAbs001, 0], radius = 8)', expectFinal: 'circle(center = [xAbs001, 0], radius = 8)',
@ -1013,8 +1008,7 @@ profile001 = startProfileAt([56.37, 120.33], sketch001)
await clickUnconstrained({ await clickUnconstrained({
hoverPos, hoverPos,
constraintType: 'radius', constraintType: 'radius',
expectBeforeUnconstrained: expectBeforeUnconstrained: 'circle(center = [xAbs001, 0], radius = 8)',
'circle(center = [xAbs001, 0], radius = 8)',
expectAfterUnconstrained: expectAfterUnconstrained:
'circle(center = [xAbs001, 0], radius = radius001)', 'circle(center = [xAbs001, 0], radius = radius001)',
expectFinal: 'circle(center = [xAbs001, 0], radius = 8)', expectFinal: 'circle(center = [xAbs001, 0], radius = 8)',
@ -1023,8 +1017,7 @@ profile001 = startProfileAt([56.37, 120.33], sketch001)
locator: '[data-overlay-toolbar-index="0"]', locator: '[data-overlay-toolbar-index="0"]',
}) })
}) })
} })
)
test.describe('Testing deleting a segment', () => { test.describe('Testing deleting a segment', () => {
const _deleteSegmentSequence = const _deleteSegmentSequence =
(page: Page, editor: EditorFixture) => (page: Page, editor: EditorFixture) =>

View File

@ -448,9 +448,14 @@ profile003 = startProfileAt([40.16, -120.48], sketch006)
await page.waitForTimeout(200) await page.waitForTimeout(200)
await expect(u.codeLocator).not.toContainText(codeToBeDeletedSnippet) await expect(u.codeLocator).not.toContainText(codeToBeDeletedSnippet)
}) })
test.fixme( test('parent Solid should be select and deletable and uses custom planes to position children', async ({
'parent Solid should be select and deletable and uses custom planes to position children', page,
async ({ page, homePage, scene, cmdBar, editor }) => { homePage,
scene,
cmdBar,
editor,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
test.setTimeout(90_000) test.setTimeout(90_000)
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
@ -514,8 +519,7 @@ profile001 = startProfileAt([7.49, 9.96], sketch001)
shouldNormalise: true, shouldNormalise: true,
}) })
await editor.snapshot() await editor.snapshot()
} })
)
test('Hovering over 3d features highlights code, clicking puts the cursor in the right place and sends selection id to engine', async ({ test('Hovering over 3d features highlights code, clicking puts the cursor in the right place and sends selection id to engine', async ({
page, page,
homePage, homePage,

View File

@ -55,9 +55,11 @@ test.describe('Testing settings', () => {
}) })
// The behavior is actually broken. Parent always takes precedence // The behavior is actually broken. Parent always takes precedence
test.fixme( test('Project settings can be set and override user settings', async ({
'Project settings can be set and override user settings', page,
async ({ page, homePage }) => { homePage,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const u = await getUtils(page) const u = await getUtils(page)
await test.step(`Setup`, async () => { await test.step(`Setup`, async () => {
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
@ -82,14 +84,11 @@ test.describe('Testing settings', () => {
/** Test to close https://github.com/KittyCAD/modeling-app/issues/2713 */ /** Test to close https://github.com/KittyCAD/modeling-app/issues/2713 */
await test.step(`Confirm that this dialog has a solid background`, async () => { await test.step(`Confirm that this dialog has a solid background`, async () => {
await expect await expect
.poll( .poll(() => u.getGreatestPixDiff({ x: 600, y: 250 }, [28, 28, 28]), {
() => u.getGreatestPixDiff({ x: 600, y: 250 }, [28, 28, 28]),
{
timeout: 1000, timeout: 1000,
message: message:
'Checking for solid background, should not see default plane colors', 'Checking for solid background, should not see default plane colors',
} })
)
.toBeLessThan(15) .toBeLessThan(15)
}) })
@ -122,9 +121,7 @@ test.describe('Testing settings', () => {
// Roll back to default of "off" // Roll back to default of "off"
await await page await await page
.getByText( .getByText('show debug panelRoll back show debug panelRoll back to match')
'show debug panelRoll back show debug panelRoll back to match'
)
.hover() .hover()
await page await page
.getByRole('button', { .getByRole('button', {
@ -138,8 +135,7 @@ test.describe('Testing settings', () => {
await expect( await expect(
page.locator('input[name="app-showDebugPanel"]') page.locator('input[name="app-showDebugPanel"]')
).not.toBeChecked() ).not.toBeChecked()
} })
)
test('Keybindings display the correct hotkey for Command Palette', async ({ test('Keybindings display the correct hotkey for Command Palette', async ({
page, page,
@ -175,9 +171,8 @@ test.describe('Testing settings', () => {
await expect(hotkey).toHaveText(text) await expect(hotkey).toHaveText(text)
}) })
test.fixme( test('Project and user settings can be reset', async ({ page, homePage }) => {
'Project and user settings can be reset', test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
await test.step(`Setup`, async () => { await test.step(`Setup`, async () => {
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
@ -261,17 +256,13 @@ test.describe('Testing settings', () => {
await expect(themeColorSetting).toHaveValue(settingValues.project) await expect(themeColorSetting).toHaveValue(settingValues.project)
}) })
}) })
} })
)
test.fixme( test(
`Project settings override user settings on desktop`, `Project settings override user settings on desktop`,
{ tag: ['@electron', '@skipWin'] }, { tag: ['@electron', '@skipWin'] },
async ({ context, page }, testInfo) => { async ({ context, page }, testInfo) => {
test.skip( test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const projectName = 'bracket' const projectName = 'bracket'
const { dir: projectDirName } = await context.folderSetupFn( const { dir: projectDirName } = await context.folderSetupFn(
async (dir) => { async (dir) => {
@ -407,12 +398,13 @@ test.describe('Testing settings', () => {
) )
// It was much easier to test the logo color than the background stream color. // It was much easier to test the logo color than the background stream color.
test.fixme( test(
'user settings reload on external change, on project and modeling view', 'user settings reload on external change, on project and modeling view',
{ {
tag: '@electron', tag: '@electron',
}, },
async ({ context, page, tronApp }, testInfo) => { async ({ context, page, tronApp }, testInfo) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
if (!tronApp) { if (!tronApp) {
fail() fail()
} }
@ -466,10 +458,11 @@ test.describe('Testing settings', () => {
} }
) )
test.fixme( test(
'project settings reload on external change', 'project settings reload on external change',
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, page }, testInfo) => { async ({ context, page }, testInfo) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const { dir: projectDirName } = await context.folderSetupFn( const { dir: projectDirName } = await context.folderSetupFn(
async () => {} async () => {}
) )
@ -982,9 +975,15 @@ fn cube`
/** /**
* This test assumes that the default value of the "highlight edges" setting is "on". * This test assumes that the default value of the "highlight edges" setting is "on".
*/ */
test.fixme( test(`Toggle stream settings multiple times`, async ({
`Toggle stream settings multiple times`, page,
async ({ page, scene, homePage, context, toolbar, cmdBar }, testInfo) => { scene,
homePage,
context,
toolbar,
cmdBar,
}, testInfo) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const projectDir = join(dir, 'project-000') const projectDir = join(dir, 'project-000')
await fsp.mkdir(projectDir, { recursive: true }) await fsp.mkdir(projectDir, { recursive: true })
@ -1039,6 +1038,5 @@ fn cube`
mask: [page.getByTestId('model-state-indicator')], mask: [page.getByTestId('model-state-indicator')],
} }
) )
} })
)
}) })

View File

@ -431,10 +431,11 @@ test.describe('Text-to-CAD tests', { tag: ['@skipWin'] }, () => {
}) })
// This will be fine once greg makes prompt at top of file deterministic // This will be fine once greg makes prompt at top of file deterministic
test.fixme( test(
'can do many at once and get many prompts back, and interact with many', 'can do many at once and get many prompts back, and interact with many',
{ tag: ['@skipWin'] }, { tag: ['@skipWin'] },
async ({ page, homePage }) => { async ({ page, homePage }) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
// Let this test run longer since we've seen it timeout. // Let this test run longer since we've seen it timeout.
test.setTimeout(180_000) test.setTimeout(180_000)
@ -619,10 +620,11 @@ async function sendPromptFromCommandBar(page: Page, promptStr: string) {
}) })
} }
test.fixme( test(
'Text-to-CAD functionality', 'Text-to-CAD functionality',
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, page }, testInfo) => { async ({ context, page }, testInfo) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const projectName = 'project-000' const projectName = 'project-000'
const prompt = 'lego 2x4' const prompt = 'lego 2x4'
const textToCadFileName = 'lego-2x4.kcl' const textToCadFileName = 'lego-2x4.kcl'

View File

@ -2,7 +2,8 @@ import { test, expect } from './zoo-test'
import { doExport, getUtils, makeTemplate } from './test-utils' import { doExport, getUtils, makeTemplate } from './test-utils'
test.fixme('Units menu', async ({ page, homePage }) => { test('Units menu', async ({ page, homePage }) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
@ -263,9 +264,11 @@ test('First escape in tool pops you out of tool, second exits sketch mode', asyn
).not.toBeVisible() ).not.toBeVisible()
}) })
test.fixme( test('Basic default modeling and sketch hotkeys work', async ({
'Basic default modeling and sketch hotkeys work', page,
async ({ page, homePage }) => { homePage,
}) => {
test.fixme(process.env.GITHUB_HEAD_REF !== 'all-e2e')
const u = await getUtils(page) const u = await getUtils(page)
// This test can run long if it takes a little too long to load // This test can run long if it takes a little too long to load
@ -441,8 +444,7 @@ test.fixme(
await page.keyboard.press('Escape') await page.keyboard.press('Escape')
await page.waitForTimeout(100) await page.waitForTimeout(100)
} }
} })
)
test('Delete key does not navigate back', async ({ page, homePage }) => { test('Delete key does not navigate back', async ({ page, homePage }) => {
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })