diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 155160e88..8908acd98 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -81,6 +81,31 @@ jobs: - name: Run codespell run: codespell --config .codespellrc # Edit this file to tweak the typo list and other configuration. + yarn-unit-test-kcl-samples: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + + - run: yarn install + - run: yarn build:wasm + + - run: yarn simpleserver:bg + if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} + + - name: Install Chromium Browser + if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} + run: yarn playwright install chromium --with-deps + + - name: run unit tests for kcl samples + if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} + run: yarn test:unit:kcl-samples + env: + VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} yarn-unit-test: runs-on: ubuntu-latest diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-2-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-2-Google-Chrome-linux.png index 1ea5160b9..3a24ee84c 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-2-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-2-Google-Chrome-linux.png differ diff --git a/package.json b/package.json index 8dcb66e2a..fc0cc2156 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,8 @@ "tronb:package": "electron-builder --config electron-builder.yml", "test-setup": "yarn install && yarn build:wasm", "test": "vitest --mode development", - "test:unit": "vitest run --mode development", + "test:unit": "vitest run --mode development --exclude **/kclSamples.test.ts", + "test:unit:kcl-samples": "vitest run --mode development ./src/lang/kclSamples.test.ts", "test:playwright:browser:chrome": "playwright test --project='Google Chrome' --config=playwright.ci.config.ts --grep-invert='@snapshot|@electron'", "test:playwright:browser:chrome:windows": "playwright test --project=\"Google Chrome\" --config=playwright.ci.config.ts --grep-invert=\"@snapshot|@electron|@skipWin\"", "test:playwright:browser:chrome:ubuntu": "playwright test --project='Google Chrome' --config=playwright.ci.config.ts --grep-invert='@snapshot|@electron|@skipLinux'", @@ -117,7 +118,8 @@ "test:playwright:electron:windows:local": "yarn tron:package && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep=@electron --grep-invert=@skipWin", "test:playwright:electron:macos:local": "yarn tron:package && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep=@electron --grep-invert=@skipMacos", "test:playwright:electron:ubuntu:local": "yarn tron:package && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep=@electron --grep-invert=@skipLinux", - "test:unit:local": "yarn simpleserver:bg && yarn test:unit; kill-port 3000" + "test:unit:local": "yarn simpleserver:bg && yarn test:unit; kill-port 3000", + "test:unit:kcl-samples:local": "yarn simpleserver:bg && yarn test:unit:kcl-samples; kill-port 3000" }, "prettier": { "trailingComma": "es5", diff --git a/src/lang/kclSamples.test.ts b/src/lang/kclSamples.test.ts new file mode 100644 index 000000000..1e1a7d021 --- /dev/null +++ b/src/lang/kclSamples.test.ts @@ -0,0 +1,87 @@ +import { parse, initPromise, programMemoryInit } from './wasm' +import { enginelessExecutor } from '../lib/testHelpers' +import { assert } from 'vitest' +// These unit tests makes web requests to a public github repository. + +interface KclSampleFile { + file: string + title: string + filename: string + description: string +} + +beforeAll(async () => { + await initPromise +}) + +// Only used to actually fetch an older version of KCL code that will break in the parser. +/* eslint-disable @typescript-eslint/no-unused-vars */ +async function getBrokenSampleCodeForLocalTesting() { + const result = await fetch( + 'https://raw.githubusercontent.com/KittyCAD/kcl-samples/5ccd04a1773ebdbfd02684057917ce5dbe0eaab3/80-20-rail.kcl' + ) + const text = await result.text() + return text +} + +async function getKclSampleCodeFromGithub(file: string): Promise { + const result = await fetch( + `https://raw.githubusercontent.com/KittyCAD/kcl-samples/refs/heads/main/${file}/${file}.kcl` + ) + const text = await result.text() + return text +} + +async function getFileNamesFromManifestJSON(): Promise { + const result = await fetch( + 'https://raw.githubusercontent.com/KittyCAD/kcl-samples/refs/heads/main/manifest.json' + ) + const json = await result.json() + json.forEach((file: KclSampleFile) => { + const filenameWithoutExtension = file.file.split('.')[0] + file.filename = filenameWithoutExtension + }) + return json +} + +// Value to use across all tests! +let files: KclSampleFile[] = [] + +describe('Test KCL Samples from public Github repository', () => { + describe('When parsing source code', () => { + // THIS RUNS ACROSS OTHER TESTS! + it('should fetch files', async () => { + files = await getFileNamesFromManifestJSON() + }) + // Run through all of the files in the manifest json. This will allow us to be automatically updated + // with the latest changes in github. We won't be hard coding the filenames + it( + 'should run through all the files', + async () => { + for (let i = 0; i < files.length; i++) { + const file: KclSampleFile = files[i] + const code = await getKclSampleCodeFromGithub(file.filename) + const parsed = parse(code) + assert(!(parsed instanceof Error)) + } + }, + files.length * 1000 + ) + }) + + describe('when performing enginelessExecutor', () => { + it( + 'should run through all the files', + async () => { + for (let i = 0; i < files.length; i++) { + const file: KclSampleFile = files[i] + const code = await getKclSampleCodeFromGithub(file.filename) + const parsed = parse(code) + assert(!(parsed instanceof Error)) + await enginelessExecutor(parsed, programMemoryInit()) + } + }, + files.length * 1000 + ) + }) +})