Compare commits
1 Commits
kurt-test-
...
kurt-does-
| Author | SHA1 | Date | |
|---|---|---|---|
| d2a3bfdb5a |
4
.github/workflows/playwright.yml
vendored
4
.github/workflows/playwright.yml
vendored
@ -423,14 +423,14 @@ jobs:
|
|||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
if: ${{ !cancelled() && (success() || failure()) }}
|
if: ${{ !cancelled() && (success() || failure()) }}
|
||||||
with:
|
with:
|
||||||
name: test-results-electron-${{ matrix.os }}-${{ github.sha }}
|
name: test-results-electron-${{ github.sha }}
|
||||||
path: test-results/
|
path: test-results/
|
||||||
retention-days: 30
|
retention-days: 30
|
||||||
overwrite: true
|
overwrite: true
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
if: ${{ !cancelled() && (success() || failure()) }}
|
if: ${{ !cancelled() && (success() || failure()) }}
|
||||||
with:
|
with:
|
||||||
name: playwright-report-electron-${{ matrix.os }}-${{ github.sha }}
|
name: playwright-report-electron-${{ github.sha }}
|
||||||
path: playwright-report/
|
path: playwright-report/
|
||||||
retention-days: 30
|
retention-days: 30
|
||||||
overwrite: true
|
overwrite: true
|
||||||
|
|||||||
@ -110,6 +110,7 @@ Which commands from setup are one off vs need to be run every time?
|
|||||||
The following will need to be run when checking out a new commit and guarantees the build is not stale:
|
The following will need to be run when checking out a new commit and guarantees the build is not stale:
|
||||||
```bash
|
```bash
|
||||||
yarn install
|
yarn install
|
||||||
|
yarn wasm-prep
|
||||||
yarn build:wasm-dev # or yarn build:wasm for slower but more production-like build
|
yarn build:wasm-dev # or yarn build:wasm for slower but more production-like build
|
||||||
yarn start # or yarn build:local && yarn serve for slower but more production-like build
|
yarn start # or yarn build:local && yarn serve for slower but more production-like build
|
||||||
```
|
```
|
||||||
|
|||||||
@ -6,8 +6,6 @@ import {
|
|||||||
setupElectron,
|
setupElectron,
|
||||||
createProjectAndRenameIt,
|
createProjectAndRenameIt,
|
||||||
} from './test-utils'
|
} from './test-utils'
|
||||||
import { join } from 'path'
|
|
||||||
import fs from 'fs'
|
|
||||||
|
|
||||||
test.beforeEach(async ({ context, page }) => {
|
test.beforeEach(async ({ context, page }) => {
|
||||||
await setup(context, page)
|
await setup(context, page)
|
||||||
@ -696,9 +694,10 @@ test(
|
|||||||
'Text-to-CAD functionality',
|
'Text-to-CAD functionality',
|
||||||
{ tag: '@electron' },
|
{ tag: '@electron' },
|
||||||
async ({ browserName }, testInfo) => {
|
async ({ browserName }, testInfo) => {
|
||||||
const { electronApp, page, dir } = await setupElectron({ testInfo })
|
const { electronApp, page } = await setupElectron({
|
||||||
const fileExists = () =>
|
testInfo,
|
||||||
fs.existsSync(join(dir, 'test-000', 'lego-2x4.kcl'))
|
folderSetupFn: async () => {},
|
||||||
|
})
|
||||||
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
await page.setViewportSize({ width: 1200, height: 500 })
|
||||||
|
|
||||||
@ -722,7 +721,6 @@ test(
|
|||||||
// File is considered created if it shows up in the Project Files pane
|
// File is considered created if it shows up in the Project Files pane
|
||||||
const file = page.getByRole('button', { name: 'lego-2x4.kcl' })
|
const file = page.getByRole('button', { name: 'lego-2x4.kcl' })
|
||||||
await expect(file).toBeVisible({ timeout: 20_000 })
|
await expect(file).toBeVisible({ timeout: 20_000 })
|
||||||
expect(fileExists()).toBeTruthy()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await test.step(`Test file navigation`, async () => {
|
await test.step(`Test file navigation`, async () => {
|
||||||
@ -743,7 +741,6 @@ test(
|
|||||||
`Successfully deleted file "lego-2x4.kcl"`
|
`Successfully deleted file "lego-2x4.kcl"`
|
||||||
)
|
)
|
||||||
await expect(submittingToastMessage).toBeVisible()
|
await expect(submittingToastMessage).toBeVisible()
|
||||||
expect(fileExists()).toBeFalsy()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await electronApp.close()
|
await electronApp.close()
|
||||||
|
|||||||
@ -83,10 +83,11 @@
|
|||||||
"fmt-check": "prettier --check ./src *.ts *.json *.js ./e2e ./packages",
|
"fmt-check": "prettier --check ./src *.ts *.json *.js ./e2e ./packages",
|
||||||
"fetch:wasm": "./get-latest-wasm-bundle.sh",
|
"fetch:wasm": "./get-latest-wasm-bundle.sh",
|
||||||
"isomorphic-copy-wasm": "(copy src/wasm-lib/pkg/wasm_lib_bg.wasm public || cp src/wasm-lib/pkg/wasm_lib_bg.wasm public)",
|
"isomorphic-copy-wasm": "(copy src/wasm-lib/pkg/wasm_lib_bg.wasm public || cp src/wasm-lib/pkg/wasm_lib_bg.wasm public)",
|
||||||
"build:wasm-dev": "yarn wasm-prep && (cd src/wasm-lib && wasm-pack build --dev --target web --out-dir pkg && cargo test -p kcl-lib export_bindings) && yarn isomorphic-copy-wasm && yarn fmt",
|
"build:wasm-dev": "(cd src/wasm-lib && wasm-pack build --dev --target web --out-dir pkg && cargo test -p kcl-lib export_bindings) && yarn isomorphic-copy-wasm && yarn fmt",
|
||||||
"build:wasm": "yarn wasm-prep && cd src/wasm-lib && wasm-pack build --release --target web --out-dir pkg && cargo test -p kcl-lib export_bindings && cd ../.. && yarn isomorphic-copy-wasm && yarn fmt",
|
"build:wasm": "cd src/wasm-lib && wasm-pack build --release --target web --out-dir pkg && cargo test -p kcl-lib export_bindings && cd ../.. && yarn isomorphic-copy-wasm && yarn fmt",
|
||||||
|
"build:wasm-clean": "yarn wasm-prep && yarn build:wasm",
|
||||||
"remove-importmeta": "sed -i 's/import.meta.url/window.location.origin/g' \"./src/wasm-lib/pkg/wasm_lib.js\"; sed -i '' 's/import.meta.url/window.location.origin/g' \"./src/wasm-lib/pkg/wasm_lib.js\" || echo \"sed for both mac and linux\"",
|
"remove-importmeta": "sed -i 's/import.meta.url/window.location.origin/g' \"./src/wasm-lib/pkg/wasm_lib.js\"; sed -i '' 's/import.meta.url/window.location.origin/g' \"./src/wasm-lib/pkg/wasm_lib.js\" || echo \"sed for both mac and linux\"",
|
||||||
"wasm-prep": "rimraf src/wasm-lib/pkg && mkdirp src/wasm-lib/pkg && rimraf src/wasm-lib/kcl/bindings",
|
"wasm-prep": "rm -rf src/wasm-lib/pkg && mkdir src/wasm-lib/pkg && rm -rf src/wasm-lib/kcl/bindings",
|
||||||
"lint": "eslint --fix src e2e",
|
"lint": "eslint --fix src e2e",
|
||||||
"bump-jsons": "echo \"$(jq --arg v \"$VERSION\" '.version=$v' package.json --indent 2)\" > package.json",
|
"bump-jsons": "echo \"$(jq --arg v \"$VERSION\" '.version=$v' package.json --indent 2)\" > package.json",
|
||||||
"postinstall": "yarn xstate:typegen && ./node_modules/.bin/electron-rebuild",
|
"postinstall": "yarn xstate:typegen && ./node_modules/.bin/electron-rebuild",
|
||||||
|
|||||||
@ -152,7 +152,7 @@ const extrude001 = extrude(-15, sketch001)`
|
|||||||
selectedSegmentSnippet,
|
selectedSegmentSnippet,
|
||||||
expectedExtrudeSnippet
|
expectedExtrudeSnippet
|
||||||
)
|
)
|
||||||
}, 5_000)
|
})
|
||||||
it('should return the correct paths for a valid selection and extrusion in case of several extrusions and sketches', async () => {
|
it('should return the correct paths for a valid selection and extrusion in case of several extrusions and sketches', async () => {
|
||||||
const code = `const sketch001 = startSketchOn('XY')
|
const code = `const sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-30, 30], %)
|
|> startProfileAt([-30, 30], %)
|
||||||
|
|||||||
@ -469,9 +469,6 @@ export const hasValidFilletSelection = ({
|
|||||||
if (segmentNode.node.type === 'CallExpression') {
|
if (segmentNode.node.type === 'CallExpression') {
|
||||||
const segmentName = segmentNode.node.callee.name
|
const segmentName = segmentNode.node.callee.name
|
||||||
if (segmentName in sketchLineHelperMap) {
|
if (segmentName in sketchLineHelperMap) {
|
||||||
// Add check whether the tag exists at all:
|
|
||||||
if (!(segmentNode.node.arguments.length === 3)) return true
|
|
||||||
// If the tag exists, check if it is already filleted
|
|
||||||
const edges = isTagUsedInFillet({
|
const edges = isTagUsedInFillet({
|
||||||
ast,
|
ast,
|
||||||
callExp: segmentNode.node,
|
callExp: segmentNode.node,
|
||||||
|
|||||||
@ -60,7 +60,6 @@ export const TEST_SETTINGS_FILE_KEY = 'playwright-test-settings'
|
|||||||
|
|
||||||
export const DEFAULT_HOST = 'https://api.zoo.dev'
|
export const DEFAULT_HOST = 'https://api.zoo.dev'
|
||||||
export const SETTINGS_FILE_NAME = 'settings.toml'
|
export const SETTINGS_FILE_NAME = 'settings.toml'
|
||||||
export const TOKEN_FILE_NAME = 'token.txt'
|
|
||||||
export const PROJECT_SETTINGS_FILE_NAME = 'project.toml'
|
export const PROJECT_SETTINGS_FILE_NAME = 'project.toml'
|
||||||
export const COOKIE_NAME = '__Secure-next-auth.session-token'
|
export const COOKIE_NAME = '__Secure-next-auth.session-token'
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import {
|
|||||||
PROJECT_FOLDER,
|
PROJECT_FOLDER,
|
||||||
PROJECT_SETTINGS_FILE_NAME,
|
PROJECT_SETTINGS_FILE_NAME,
|
||||||
SETTINGS_FILE_NAME,
|
SETTINGS_FILE_NAME,
|
||||||
TOKEN_FILE_NAME,
|
|
||||||
} from './constants'
|
} from './constants'
|
||||||
import { DeepPartial } from './types'
|
import { DeepPartial } from './types'
|
||||||
import { ProjectConfiguration } from 'wasm-lib/kcl/bindings/ProjectConfiguration'
|
import { ProjectConfiguration } from 'wasm-lib/kcl/bindings/ProjectConfiguration'
|
||||||
@ -397,23 +396,6 @@ const getAppSettingsFilePath = async () => {
|
|||||||
}
|
}
|
||||||
return window.electron.path.join(fullPath, SETTINGS_FILE_NAME)
|
return window.electron.path.join(fullPath, SETTINGS_FILE_NAME)
|
||||||
}
|
}
|
||||||
const getTokenFilePath = async () => {
|
|
||||||
const isTestEnv = window.electron.process.env.IS_PLAYWRIGHT === 'true'
|
|
||||||
const testSettingsPath = window.electron.process.env.TEST_SETTINGS_FILE_KEY
|
|
||||||
const appConfig = await window.electron.getPath('appData')
|
|
||||||
const fullPath = isTestEnv
|
|
||||||
? testSettingsPath
|
|
||||||
: window.electron.path.join(appConfig, getAppFolderName())
|
|
||||||
try {
|
|
||||||
await window.electron.stat(fullPath)
|
|
||||||
} catch (e) {
|
|
||||||
// File/path doesn't exist
|
|
||||||
if (e === 'ENOENT') {
|
|
||||||
await window.electron.mkdir(fullPath, { recursive: true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return window.electron.path.join(fullPath, TOKEN_FILE_NAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getProjectSettingsFilePath = async (projectPath: string) => {
|
const getProjectSettingsFilePath = async (projectPath: string) => {
|
||||||
try {
|
try {
|
||||||
@ -493,34 +475,6 @@ export const writeAppSettingsFile = async (tomlStr: string) => {
|
|||||||
return window.electron.writeFile(appSettingsFilePath, tomlStr)
|
return window.electron.writeFile(appSettingsFilePath, tomlStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const readTokenFile = async () => {
|
|
||||||
let settingsPath = await getTokenFilePath()
|
|
||||||
|
|
||||||
if (window.electron.exists(settingsPath)) {
|
|
||||||
const token: string = await window.electron.readFile(settingsPath)
|
|
||||||
if (!token) return ''
|
|
||||||
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
export const writeTokenFile = async (token: string) => {
|
|
||||||
const tokenFilePath = await getTokenFilePath()
|
|
||||||
if (err(token)) return Promise.reject(token)
|
|
||||||
return window.electron.writeFile(tokenFilePath, token)
|
|
||||||
}
|
|
||||||
|
|
||||||
let appStateStore: Project | undefined = undefined
|
|
||||||
|
|
||||||
export const getState = async (): Promise<Project | undefined> => {
|
|
||||||
return Promise.resolve(appStateStore)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const setState = async (state: Project | undefined): Promise<void> => {
|
|
||||||
appStateStore = state
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getUser = async (
|
export const getUser = async (
|
||||||
token: string,
|
token: string,
|
||||||
hostname: string
|
hostname: string
|
||||||
|
|||||||
@ -147,7 +147,7 @@ export function platform(): Platform {
|
|||||||
case 'sunos':
|
case 'sunos':
|
||||||
return 'linux'
|
return 'linux'
|
||||||
default:
|
default:
|
||||||
console.error('Unknown desktop platform:', platform)
|
console.error('Unknown platform:', platform)
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,14 +156,11 @@ export function platform(): Platform {
|
|||||||
// it's more accurate than userAgent and userAgentData in Playwright.
|
// it's more accurate than userAgent and userAgentData in Playwright.
|
||||||
if (
|
if (
|
||||||
navigator.platform?.indexOf('Mac') === 0 ||
|
navigator.platform?.indexOf('Mac') === 0 ||
|
||||||
navigator.platform?.indexOf('iPhone') === 0 ||
|
navigator.platform === 'iPhone'
|
||||||
navigator.platform?.indexOf('iPad') === 0 ||
|
|
||||||
// Vite tests running in HappyDOM.
|
|
||||||
navigator.platform?.indexOf('Darwin') >= 0
|
|
||||||
) {
|
) {
|
||||||
return 'macos'
|
return 'macos'
|
||||||
}
|
}
|
||||||
if (navigator.platform === 'Windows' || navigator.platform === 'Win32') {
|
if (navigator.platform === 'Win32') {
|
||||||
return 'windows'
|
return 'windows'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +185,7 @@ export function platform(): Platform {
|
|||||||
return 'linux'
|
return 'linux'
|
||||||
}
|
}
|
||||||
console.error(
|
console.error(
|
||||||
'Unknown web platform:',
|
'Unknown platform userAgent:',
|
||||||
navigator.platform,
|
navigator.platform,
|
||||||
userAgentDataPlatform,
|
userAgentDataPlatform,
|
||||||
navigator.userAgent
|
navigator.userAgent
|
||||||
|
|||||||
@ -8,11 +8,7 @@ import {
|
|||||||
VITE_KC_SKIP_AUTH,
|
VITE_KC_SKIP_AUTH,
|
||||||
DEV,
|
DEV,
|
||||||
} from 'env'
|
} from 'env'
|
||||||
import {
|
import { getUser as getUserDesktop } from 'lib/desktop'
|
||||||
getUser as getUserDesktop,
|
|
||||||
readTokenFile,
|
|
||||||
writeTokenFile,
|
|
||||||
} from 'lib/desktop'
|
|
||||||
import { COOKIE_NAME } from 'lib/constants'
|
import { COOKIE_NAME } from 'lib/constants'
|
||||||
|
|
||||||
const SKIP_AUTH = VITE_KC_SKIP_AUTH === 'true' && DEV
|
const SKIP_AUTH = VITE_KC_SKIP_AUTH === 'true' && DEV
|
||||||
@ -57,7 +53,6 @@ const persistedToken =
|
|||||||
|
|
||||||
export const authMachine = createMachine<UserContext, Events>(
|
export const authMachine = createMachine<UserContext, Events>(
|
||||||
{
|
{
|
||||||
/** @xstate-layout N4IgpgJg5mDOIC5QEECuAXAFgOgMabFwGsBJAMwBkB7KGCEgOwGIIqGxsBLBgNyqI75CRALQAbGnRHcA2gAYAuolAAHKrE7pObZSAAeiAIwBmAEzYA7ABYAbAFZTcgBzGbN44adWANCACeiKbGdthypk4AnBFyVs6uQXYAvom+aFh4BMTk1LSQjExgAE6FVIXYKmIAhuhkpQC2GcLikpDSDPJKSCBqGlo6XQYIrk7YETYWctYRxmMWFk6+AUPj2I5OdjZyrnZOFmbJqRg4Ern0zDkABFQYHbo9mtoMuoOGFhHYxlZOhvbOsUGGRaIL4WbBONzWQxWYwWOx2H4HEBpY4tCAAeQwTEuskUd3UD36oEGIlMNlCuzk8Js0TcVisgP8iG2lmcGysb0mW3ByRSIAYVAgcF0yLxvUez0QIms5ImVJpNjpDKWxmw9PGdLh4Te00+iORjSylFRjFFBKeA0QThGQWcexMwWhniBCGiqrepisUVMdlszgieqO2BOdBNXXufXNRKMHtGVuphlJkXs4Wdriso2CCasdgipOidID6WDkAx6FNEYlCAT5jmcjrckMdj2b3GzpsjbBMVMWezDbGPMSQA */
|
|
||||||
id: 'Auth',
|
id: 'Auth',
|
||||||
initial: 'checkIfLoggedIn',
|
initial: 'checkIfLoggedIn',
|
||||||
states: {
|
states: {
|
||||||
@ -90,9 +85,6 @@ export const authMachine = createMachine<UserContext, Events>(
|
|||||||
on: {
|
on: {
|
||||||
'Log out': {
|
'Log out': {
|
||||||
target: 'loggedOut',
|
target: 'loggedOut',
|
||||||
actions: () => {
|
|
||||||
if (isDesktop()) writeTokenFile('')
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -104,6 +96,7 @@ export const authMachine = createMachine<UserContext, Events>(
|
|||||||
actions: assign({
|
actions: assign({
|
||||||
token: (_, event) => {
|
token: (_, event) => {
|
||||||
const token = event.token || ''
|
const token = event.token || ''
|
||||||
|
localStorage.setItem(TOKEN_PERSIST_KEY, token)
|
||||||
return token
|
return token
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -127,7 +120,11 @@ export const authMachine = createMachine<UserContext, Events>(
|
|||||||
)
|
)
|
||||||
|
|
||||||
async function getUser(context: UserContext) {
|
async function getUser(context: UserContext) {
|
||||||
const token = await getAndSyncStoredToken(context)
|
const token = VITE_KC_DEV_TOKEN
|
||||||
|
? VITE_KC_DEV_TOKEN
|
||||||
|
: context.token && context.token !== ''
|
||||||
|
? context.token
|
||||||
|
: getCookie(COOKIE_NAME) || localStorage?.getItem(TOKEN_PERSIST_KEY)
|
||||||
const url = withBaseURL('/user')
|
const url = withBaseURL('/user')
|
||||||
const headers: { [key: string]: string } = {
|
const headers: { [key: string]: string } = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@ -192,26 +189,3 @@ function getCookie(cname: string): string | null {
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAndSyncStoredToken(context: UserContext): Promise<string> {
|
|
||||||
// dev mode
|
|
||||||
if (VITE_KC_DEV_TOKEN) return VITE_KC_DEV_TOKEN
|
|
||||||
|
|
||||||
const token =
|
|
||||||
context.token && context.token !== ''
|
|
||||||
? context.token
|
|
||||||
: getCookie(COOKIE_NAME) || localStorage?.getItem(TOKEN_PERSIST_KEY) || ''
|
|
||||||
if (token) {
|
|
||||||
// has just logged in, update storage
|
|
||||||
localStorage.setItem(TOKEN_PERSIST_KEY, token)
|
|
||||||
isDesktop() && writeTokenFile(token)
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
if (!isDesktop()) return ''
|
|
||||||
const fileToken = isDesktop() ? await readTokenFile() : ''
|
|
||||||
// prefer other above, but file will ensure login persists after app updates
|
|
||||||
if (!fileToken) return ''
|
|
||||||
// has token in file, update localStorage
|
|
||||||
localStorage.setItem(TOKEN_PERSIST_KEY, fileToken)
|
|
||||||
return fileToken
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user