mirror of
https://github.com/enso-org/enso.git
synced 2024-12-22 21:01:37 +03:00
Unify Frontend App (#11287)
Fixes #10668 Fixes #8484 Summary of changes: * `gui2` and `dashboard` are merged to `gui` directory. Various configs were merged (package.json, playwrigth, TS...). The src and e2e directories are split to `dashboard` and `project-view` for now. * E2E tests run two servers on different ports. The tests are organized in projects. This is also to be changed soon, as we plan to [use better mocking in GUI/ProjectView](#9726) * ESlint configs were merged to central `eslint.config.mjs`, and that file was moved to repository root. We kept the dashboard lints, but they can be relaxed. The dashboard code was changed to meet GUI lints. * Also, the versions of linter plugins were bumped, and code fixed. * The ide-desktop/client no longer has `dashboard` dependency - the only type used there was moved to common package. * `common` package moved to `app`.
This commit is contained in:
parent
204b37c6c3
commit
4a249688e8
31
.github/CODEOWNERS
vendored
31
.github/CODEOWNERS
vendored
@ -19,14 +19,30 @@ Cargo.toml
|
||||
/lib/rust/parser/ @farmaazon @kazcw @vitvakatu @Frizi @jaroslavtulach @AdRiley
|
||||
/tools/build-performance/ @kazcw @Akirathan
|
||||
|
||||
# Global JS configuration
|
||||
esling.config.mjs
|
||||
tsconfig.json
|
||||
|
||||
# Scala Libraries
|
||||
/lib/scala/ @4e6 @jaroslavtulach @hubertp @Akirathan
|
||||
|
||||
# Java libraries
|
||||
/lib/java/ @4e6 @jaroslavtulach @hubertp @Akirathan
|
||||
|
||||
# GUI
|
||||
/app/gui2/ @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
|
||||
# GUI/Dashboard
|
||||
/app @Frizi @farmaazon @vitvakatu @kazcw @AdRiley @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
|
||||
/app/gui/e2e/dashboard @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
|
||||
/app/gui/e2e/project-view @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
|
||||
/app/gui/src/dashboard @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
|
||||
/app/gui/src/project-view @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
|
||||
/app/ide-desktop/ @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
|
||||
/app/ydoc-server/ @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
|
||||
/app/ydoc-server-nodejs/ @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
|
||||
/app/ydoc-server-polyglot/ @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
|
||||
/app/ydoc-shared/ @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
|
||||
# The data-link schema is owned by the libraries team
|
||||
/app/gui/src/dashboard/data/datalinkSchema.json @radeusgd @jdunkerley @GregoryTravis @AdRiley @marthasharkey
|
||||
/app/gui/src/dashboard/data/__tests__ @radeusgd @jdunkerley @GregoryTravis @AdRiley @marthasharkey @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
|
||||
|
||||
# Engine (old)
|
||||
# This section should be removed once the engine moves to /app/engine
|
||||
@ -45,14 +61,3 @@ Cargo.toml
|
||||
|
||||
# The default project template is owned by the libraries team
|
||||
/lib/scala/pkg/src/main/resources/default/src/ @radeusgd @jdunkerley @GregoryTravis @AdRiley @marthasharkey
|
||||
|
||||
# Dashboard, Cloud, Authentication & Electron
|
||||
/app/ide-desktop/ @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
|
||||
/app/dashboard/ @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
|
||||
# The data-link schema is owned by the libraries team
|
||||
/app/dashboard/src/data/datalinkSchema.json @radeusgd @jdunkerley @GregoryTravis @AdRiley @marthasharkey
|
||||
/app/dashboard/src/data/__tests__ @radeusgd @jdunkerley @GregoryTravis @AdRiley @marthasharkey @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
|
||||
|
||||
# GUI / Dashboard shared
|
||||
/app/*.* @Frizi @farmaazon @vitvakatu @kazcw @AdRiley @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
|
||||
/app/ide-desktop/common @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
|
||||
|
@ -39,10 +39,10 @@ app/ide-desktop/lib/dashboard/playwright/.cache/
|
||||
app/ide-desktop/lib/dashboard/dist/
|
||||
app/gui/view/documentation/assets/stylesheet.css
|
||||
app/rust-ffi/pkg
|
||||
app/gui2/src/assets/font-*.css
|
||||
app/gui/src/project-view/assets/font-*.css
|
||||
Cargo.lock
|
||||
build.json
|
||||
app/gui2/playwright-report/
|
||||
app/gui/playwright-report/
|
||||
|
||||
# Engine Builds can leave these nested working copies.
|
||||
# TODO [mwu]: Adjust Engine build to not leave them.
|
||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -12,7 +12,7 @@
|
||||
}
|
||||
],
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"eslint.experimental.useFlatConfig": true,
|
||||
"eslint.useFlatConfig": true,
|
||||
"eslint.useESLintClass": true,
|
||||
"[javascript][typescript][typescriptreact][vue]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
|
14
README.md
14
README.md
@ -21,7 +21,7 @@
|
||||
<img src="https://img.shields.io/static/v1?label=Compiler%20License&message=Apache%20v2&color=2ec352&labelColor=2c3239"
|
||||
alt="License">
|
||||
</a>
|
||||
<a href="https://github.com/enso-org/enso/blob/develop/app/gui2/LICENSE">
|
||||
<a href="https://github.com/enso-org/enso/blob/develop/app/gui/LICENSE">
|
||||
<img src="https://img.shields.io/static/v1?label=GUI%20License&message=AGPL%20v3&color=2ec352&labelColor=2c3239"
|
||||
alt="License">
|
||||
</a>
|
||||
@ -207,11 +207,11 @@ Enso consists of several sub projects:
|
||||
command line tools.
|
||||
|
||||
- **Enso IDE:** The
|
||||
[Enso IDE](https://github.com/enso-org/enso/tree/develop/app/gui2) is a
|
||||
desktop application that allows working with the visual form of Enso. It
|
||||
consists of an Electron application, a high performance WebGL UI framework,
|
||||
and the searcher which provides contextual search, hints, and documentation
|
||||
for all of Enso's functionality.
|
||||
[Enso IDE](https://github.com/enso-org/enso/tree/develop/app/gui) is a desktop
|
||||
application that allows working with the visual form of Enso. It consists of
|
||||
an Electron application, a high performance WebGL UI framework, and the
|
||||
searcher which provides contextual search, hints, and documentation for all of
|
||||
Enso's functionality.
|
||||
|
||||
<br/>
|
||||
|
||||
@ -222,7 +222,7 @@ The Enso Engine is licensed under the
|
||||
[LICENSE](https://github.com/enso-org/enso/blob/develop/LICENSE) file. The Enso
|
||||
IDE is licensed under the [AGPL 3.0](https://opensource.org/licenses/AGPL-3.0),
|
||||
as specified in the
|
||||
[LICENSE](https://github.com/enso-org/enso/blob/develop/app/gui2/LICENSE) file.
|
||||
[LICENSE](https://github.com/enso-org/enso/blob/develop/app/gui/LICENSE) file.
|
||||
|
||||
This license set was chosen to provide you with complete freedom to use Enso,
|
||||
create libraries, and release them under any license of your choice, while also
|
||||
|
10
app/.vscode/launch.json
vendored
10
app/.vscode/launch.json
vendored
@ -46,7 +46,7 @@
|
||||
"request": "launch",
|
||||
"name": "GUI (Storybook)",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["run", "--filter", "enso-gui2", "story:dev"],
|
||||
"runtimeArgs": ["run", "--filter", "enso-gui", "story:dev"],
|
||||
"outputCapture": "std"
|
||||
},
|
||||
{
|
||||
@ -70,7 +70,7 @@
|
||||
"request": "launch",
|
||||
"name": "GUI (E2E UI)",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["run", "--filter", "enso-gui2", "test:e2e", "--", "--ui"],
|
||||
"runtimeArgs": ["run", "--filter", "enso-gui", "test:e2e", "--", "--ui"],
|
||||
"outputCapture": "std"
|
||||
},
|
||||
{
|
||||
@ -102,14 +102,14 @@
|
||||
"request": "launch",
|
||||
"name": "GUI (All tests)",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["run", "--filter", "enso-gui2", "test"]
|
||||
"runtimeArgs": ["run", "--filter", "enso-gui", "test"]
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "GUI (E2E tests)",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["run", "--filter", "enso-gui2", "test:e2e"],
|
||||
"runtimeArgs": ["run", "--filter", "enso-gui", "test:e2e"],
|
||||
"outputCapture": "std"
|
||||
},
|
||||
{
|
||||
@ -117,7 +117,7 @@
|
||||
"request": "launch",
|
||||
"name": "GUI (Unit tests)",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["run", "--filter", "enso-gui2", "test:unit", "--", "run"],
|
||||
"runtimeArgs": ["run", "--filter", "enso-gui", "test:unit", "--", "run"],
|
||||
"outputCapture": "std"
|
||||
}
|
||||
]
|
||||
|
@ -6,6 +6,7 @@
|
||||
"exports": {
|
||||
".": "./src/index.js",
|
||||
"./src/config.json": "./src/config.json",
|
||||
"./src/accessToken": "./src/accessToken.ts",
|
||||
"./src/appConfig": "./src/appConfig.js",
|
||||
"./src/buildUtils": "./src/buildUtils.js",
|
||||
"./src/detect": "./src/detect.ts",
|
@ -445,8 +445,7 @@ export interface CheckoutSessionStatus {
|
||||
/** Status of the payment for the checkout session. */
|
||||
readonly paymentStatus: string
|
||||
/** Status of the checkout session. */
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
readonly status: 'active' | 'trialing' | (string & {})
|
||||
readonly status: 'active' | 'trialing' | (string & NonNullable<unknown>)
|
||||
}
|
||||
|
||||
/** Resource usage of a VM. */
|
@ -1,4 +0,0 @@
|
||||
playwright-report/
|
||||
playwright/.cache/
|
||||
test-results/
|
||||
dist/
|
@ -1,44 +0,0 @@
|
||||
<!--
|
||||
FIXME [NP]: https://github.com/enso-org/cloud-v2/issues/345
|
||||
This file is used by both the `content` and `dashboard` packages. The `dashboard` package uses it
|
||||
via a symlink. This is temporary, while the `content` and `dashboard` have separate entrypoints
|
||||
for cloud and desktop. Once they are merged, the symlink must be removed.
|
||||
-->
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<!-- FIXME https://github.com/validator/validator/issues/917 -->
|
||||
<!-- FIXME Security Vulnerabilities: https://github.com/enso-org/ide/issues/226 -->
|
||||
<!-- NOTE `frame-src` section of `http-equiv` required only for authorization -->
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="
|
||||
default-src 'self';
|
||||
frame-src 'self' data: https://accounts.google.com https://enso-org.firebaseapp.com;
|
||||
script-src 'self' 'unsafe-eval' data: https://*;
|
||||
style-src 'self' 'unsafe-inline' data: https://*;
|
||||
connect-src 'self' data: ws://localhost:* ws://127.0.0.1:* http://localhost:* https://* wss://*;
|
||||
worker-src 'self' blob:;
|
||||
img-src 'self' blob: data: https://*;
|
||||
font-src 'self' data: https://*"
|
||||
/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="
|
||||
width=device-width,
|
||||
initial-scale = 1.0,
|
||||
maximum-scale = 1.0,
|
||||
user-scalable = no"
|
||||
/>
|
||||
<title>Enso</title>
|
||||
<script type="module" src="./src/entrypoint.ts" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="enso-dashboard" class="enso-dashboard"></div>
|
||||
<div id="enso-chat" class="enso-chat"></div>
|
||||
<div id="enso-portal-root" class="enso-portal-root"></div>
|
||||
<noscript> This page requires JavaScript to run. Please enable it in your browser. </noscript>
|
||||
</body>
|
||||
</html>
|
@ -1,76 +0,0 @@
|
||||
# Dashboard
|
||||
|
||||
The dashboard is the entrypoint into the application. It includes project
|
||||
management, project sharing, and user accounts and authentication.
|
||||
|
||||
## Further documentation
|
||||
|
||||
Further documentation is provided in the `docs/` folder:
|
||||
|
||||
- [Browser-specific behavior](./docs/browser_specific_behavior.md) details
|
||||
behavior that is inconsistent between browsers and needs to be worked around.
|
||||
|
||||
## Folder structure
|
||||
|
||||
- `mock/`: Overrides for specific files in `src/` when running Playwright tests.
|
||||
- `e2e/`: Contains end-to-end tests.
|
||||
- `**/__tests__/`: Contains all unit tests. Unit tests MUST be in a `__tests__/`
|
||||
subfolder, not beside (and not inside) the module they are testing.
|
||||
- `src/`: The dashboard application.
|
||||
- `index.html`: The sole HTML file used by this SPA. It imports the TS entry
|
||||
point.
|
||||
- `authentication/src/`: The main body of the app.
|
||||
- `index.tsx`: The TS entry point.
|
||||
- `providers/`: Contains React `Context`s used by the main app.
|
||||
- `components/`: Contains the root component for the app.
|
||||
- `dashboard/`: The main body of the app. Directly in the folder, there are
|
||||
some utility modules that do not belong elsewhere.
|
||||
- `components/`: Contains all components used by the main app.
|
||||
- `events/`: Custom discriminated unions used to communicate messages
|
||||
between unrelated components.
|
||||
- `authentication/`: The authentication flow. This includes login,
|
||||
registration, and changing passwords.
|
||||
- `components/`: Contains all components used by the authentication flow.
|
||||
- `providers/`: Contains React `Context`s required for authentication, and
|
||||
used by the main app.
|
||||
- `index.html`: The entrypoint, in the format required by Vite.
|
||||
- `404.html`: A copy of the entrypoint. This is served on unknown routes by
|
||||
certain static hosting providers.
|
||||
- `esbuild-config.ts`: Configuration for ESBuild based on the environment
|
||||
variables. This is a dependency of `esbuild-config.ts` in sibling modules.
|
||||
|
||||
## Cloud environment variables
|
||||
|
||||
These are environment variables related to the cloud backend. If these variables
|
||||
are not set, the build will still work, however access to the cloud backend will
|
||||
be disabled.
|
||||
|
||||
Note that `ENSO_CLOUD_ENVIRONMENT` may be set to instead load the files from a
|
||||
`.env` file. If `ENSO_CLOUD_ENVIRONMENT` is not set, or it is `production` or
|
||||
`''`, then variables are attempted to be read from `.env`. If it is set to any
|
||||
other value (say, `foo`), then it is loaded from `.foo.env`.
|
||||
|
||||
(While the convention in the Node.js ecosystem is to name the variants like
|
||||
`.env.foo`, `.foo.env` has been chosen here because `.env` should be more like
|
||||
a file extension. Visual Studio Code also understands `.foo.env` but not
|
||||
`.env.foo`.)
|
||||
|
||||
- `ENSO_CLOUD_REDIRECT`: The domain (or `localhost:8080`) where the login link
|
||||
should redirect. Should include neither a path, nor a trailing slash.
|
||||
- `ENSO_CLOUD_ENVIRONMENT`: The name of backend environment matching the
|
||||
provided configuration keys. For most builds this should be `production`,
|
||||
meaning that requests go to the production cloud backend.
|
||||
- `ENSO_CLOUD_API_URL`: The root path for all API endpoints. Should not include
|
||||
a trailing slash.
|
||||
- `ENSO_CLOUD_SENTRY_DSN`: The Sentry Data Source Name (DSN) for this
|
||||
environment. This should normally be the same for all environments.
|
||||
- `ENSO_CLOUD_STRIPE_KEY`: Stripe's publishable client-side key.
|
||||
- `ENSO_CLOUD_CHAT_URL`: The URL for the WebSocket server serving as the chat
|
||||
backend.
|
||||
- `ENSO_CLOUD_COGNITO_USER_POOL_ID`: The ID of the Cognito user pool.
|
||||
- `ENSO_CLOUD_COGNITO_USER_POOL_WEB_CLIENT_ID`: The client-side key of the
|
||||
Cognito user pool.
|
||||
- `ENSO_CLOUD_COGNITO_DOMAIN`: The domain which all Cognito requests should go
|
||||
to.
|
||||
- `ENSO_CLOUD_COGNITO_REGION`: The AWS region for which Cognito is configured.
|
||||
Should match the region of the domain in `ENSO_CLOUD_COGNITO_DOMAIN`.
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
@ -1,105 +0,0 @@
|
||||
{
|
||||
"name": "enso-dashboard",
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"main": "./src/index.tsx",
|
||||
"private": true,
|
||||
"imports": {
|
||||
"#/*": "./src/*"
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.tsx",
|
||||
"./tailwind.config": "./tailwind.config.js",
|
||||
"./src/platform": "./src/platform.ts",
|
||||
"./src/tailwind.css": "./src/tailwind.css"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "tsc",
|
||||
"typecheck": "tsc",
|
||||
"build": "vite build",
|
||||
"lint": "eslint .",
|
||||
"dev": "vite",
|
||||
"dev:e2e": "vite -c vite.test.config.ts",
|
||||
"dev:e2e:ci": "vite -c vite.test.config.ts build && vite preview --port 8080 --strictPort",
|
||||
"test": "corepack pnpm run /^^^^test:.*/",
|
||||
"test:unit": "vitest run",
|
||||
"test-dev:unit": "vitest",
|
||||
"test:e2e": "cross-env NODE_ENV=production playwright test",
|
||||
"test-dev:e2e": "cross-env NODE_ENV=production playwright test --ui"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-amplify/auth": "5.6.5",
|
||||
"@aws-amplify/core": "5.8.5",
|
||||
"@hookform/resolvers": "^3.4.0",
|
||||
"@internationalized/date": "^3.5.5",
|
||||
"@monaco-editor/react": "4.6.0",
|
||||
"@react-aria/interactions": "^3.22.3",
|
||||
"@sentry/react": "^7.74.0",
|
||||
"@stripe/react-stripe-js": "^2.7.1",
|
||||
"@stripe/stripe-js": "^3.5.0",
|
||||
"@tanstack/react-query": "5.55.0",
|
||||
"@tanstack/vue-query": ">= 5.54.0 < 5.56.0",
|
||||
"ajv": "^8.12.0",
|
||||
"amazon-cognito-identity-js": "6.3.6",
|
||||
"clsx": "^2.1.1",
|
||||
"enso-common": "workspace:*",
|
||||
"framer-motion": "11.3.0",
|
||||
"input-otp": "1.2.4",
|
||||
"is-network-error": "^1.0.1",
|
||||
"monaco-editor": "0.48.0",
|
||||
"qrcode.react": "3.1.0",
|
||||
"react": "^18.3.1",
|
||||
"react-aria": "^3.34.3",
|
||||
"react-aria-components": "^1.3.3",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-error-boundary": "4.0.13",
|
||||
"react-hook-form": "^7.51.4",
|
||||
"react-router": "^6.23.1",
|
||||
"react-router-dom": "^6.23.1",
|
||||
"react-stately": "^3.32.2",
|
||||
"react-toastify": "^9.1.3",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwind-variants": "0.2.1",
|
||||
"tiny-invariant": "^1.3.3",
|
||||
"ts-results": "^3.3.0",
|
||||
"validator": "^13.12.0",
|
||||
"zod": "^3.23.8",
|
||||
"zustand": "^4.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fast-check/vitest": "^0.0.8",
|
||||
"@modyfi/vite-plugin-yaml": "^1.0.4",
|
||||
"@playwright/test": "^1.40.0",
|
||||
"@react-types/shared": "^3.22.1",
|
||||
"@tanstack/react-query-devtools": "5.45.1",
|
||||
"@types/eslint__js": "^8.42.3",
|
||||
"@types/node": "^20.11.21",
|
||||
"@types/react": "^18.0.27",
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"@types/validator": "^13.11.7",
|
||||
"@typescript-eslint/eslint-plugin": "^7.15.0",
|
||||
"@typescript-eslint/parser": "^7.15.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"chalk": "^5.3.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"enso-chat": "git://github.com/enso-org/enso-bot",
|
||||
"eslint": "^8.49.0",
|
||||
"eslint-plugin-react": "^7.32.1",
|
||||
"fast-check": "^3.15.0",
|
||||
"playwright": "^1.38.0",
|
||||
"postcss": "^8.4.29",
|
||||
"prettier-plugin-organize-imports": "^4.0.0",
|
||||
"prettier-plugin-tailwindcss": "^0.5.11",
|
||||
"react-toastify": "^9.1.3",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"tailwindcss-animate": "1.0.7",
|
||||
"tailwindcss-react-aria-components": "^1.1.1",
|
||||
"typescript": "^5.5.3",
|
||||
"vite": "^5.3.5",
|
||||
"vitest": "^1.3.1"
|
||||
},
|
||||
"overrides": {
|
||||
"@aws-amplify/auth": "../_IGNORED_",
|
||||
"react-native-url-polyfill": "../_IGNORED_"
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/** @file Playwright browser testing configuration. */
|
||||
/** Note that running Playwright in CI poses a number of issues:
|
||||
* - `backdrop-filter: blur` is disabled, due to issues with Chromium's `--disable-gpu` flag
|
||||
* (see below).
|
||||
* - System validation dialogs are not reliable between computers, as they may have different
|
||||
* default fonts. */
|
||||
import * as test from '@playwright/test'
|
||||
|
||||
import * as appConfig from 'enso-common/src/appConfig'
|
||||
|
||||
appConfig.loadTestEnvironmentVariables()
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-magic-numbers, @typescript-eslint/strict-boolean-expressions */
|
||||
|
||||
const DEBUG = process.env.PWDEBUG === '1'
|
||||
const TIMEOUT_MS = DEBUG ? 100_000_000 : 30_000
|
||||
|
||||
export default test.defineConfig({
|
||||
testDir: './e2e',
|
||||
fullyParallel: true,
|
||||
forbidOnly: true,
|
||||
workers: process.env.PROD ? 8 : 1,
|
||||
repeatEach: process.env.CI ? 3 : 1,
|
||||
expect: {
|
||||
toHaveScreenshot: { threshold: 0 },
|
||||
timeout: TIMEOUT_MS,
|
||||
},
|
||||
timeout: TIMEOUT_MS,
|
||||
reporter: 'html',
|
||||
use: {
|
||||
baseURL: 'http://localhost:8080',
|
||||
trace: 'retain-on-failure',
|
||||
launchOptions: {
|
||||
ignoreDefaultArgs: ['--headless'],
|
||||
args: [
|
||||
...(DEBUG ?
|
||||
[]
|
||||
: [
|
||||
// Much closer to headful Chromium than classic headless.
|
||||
'--headless=new',
|
||||
]),
|
||||
// Required for `backdrop-filter: blur` to work.
|
||||
'--use-angle=swiftshader',
|
||||
// FIXME: `--disable-gpu` disables `backdrop-filter: blur`, which is not handled by
|
||||
// the software (CPU) compositor. This SHOULD be fixed eventually, but this flag
|
||||
// MUST stay as CI does not have a GPU.
|
||||
'--disable-gpu',
|
||||
// Fully disable GPU process.
|
||||
'--disable-software-rasterizer',
|
||||
// Disable text subpixel antialiasing.
|
||||
'--font-render-hinting=none',
|
||||
'--disable-skia-runtime-opts',
|
||||
'--disable-system-font-check',
|
||||
'--disable-font-subpixel-positioning',
|
||||
'--disable-lcd-text',
|
||||
],
|
||||
},
|
||||
},
|
||||
webServer: {
|
||||
command: `corepack pnpm run ${process.env.CI || process.env.PROD ? 'dev:e2e:ci' : 'dev:e2e'}`,
|
||||
port: 8080,
|
||||
reuseExistingServer: false,
|
||||
},
|
||||
})
|
@ -1,9 +0,0 @@
|
||||
/** @file Configuration for PostCSS. */
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
export default {
|
||||
plugins: {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'tailwindcss/nesting': {},
|
||||
tailwindcss: {},
|
||||
},
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
/** @file Placeholder component for GUI used during e2e tests. */
|
||||
import type * as editor from '#/layouts/Editor'
|
||||
|
||||
/** Placeholder component for GUI used during e2e tests. */
|
||||
export function TestAppRunner(props: editor.GraphEditorProps) {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
return props.hidden ? <></> : <div data-testid="gui-editor-root">Vue app loads here.</div>
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 4.3 KiB |
@ -1,33 +0,0 @@
|
||||
/** @file Entry point into the cloud dashboard. */
|
||||
import * as commonQuery from 'enso-common/src/queryClient'
|
||||
|
||||
import '#/tailwind.css'
|
||||
|
||||
import * as main from '#/index'
|
||||
import * as testAppRunner from '#/TestAppRunner'
|
||||
|
||||
// ===================
|
||||
// === Entry point ===
|
||||
// ===================
|
||||
|
||||
main.run({
|
||||
logger: console,
|
||||
// Browsers usually do not support vibrancy for webpages.
|
||||
vibrancy: false,
|
||||
// This file is only included when building for the cloud.
|
||||
supportsLocalBackend: false,
|
||||
supportsDeepLinks: false,
|
||||
isAuthenticationDisabled: false,
|
||||
shouldShowDashboard: true,
|
||||
initialProjectName: null,
|
||||
/** The `onAuthenticated` option is mandatory but is not needed here,
|
||||
* so this function is empty. */
|
||||
onAuthenticated() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
},
|
||||
/** The cloud frontend is not capable of running a Project Manager. */
|
||||
projectManagerUrl: null,
|
||||
ydocUrl: null,
|
||||
appRunner: testAppRunner.TestAppRunner,
|
||||
queryClient: commonQuery.createQueryClient(),
|
||||
})
|
@ -1,23 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"include": [
|
||||
"src",
|
||||
"e2e",
|
||||
"../types",
|
||||
"./src/**/*.json",
|
||||
"./e2e/**/*.json",
|
||||
"../../utils.ts",
|
||||
".prettierrc.cjs",
|
||||
"*.js",
|
||||
"*.ts"
|
||||
],
|
||||
"exclude": ["./dist"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"noEmit": false,
|
||||
"outDir": "../../node_modules/.cache/tsc",
|
||||
"paths": { "#/*": ["./src/*"] },
|
||||
"target": "ESNext",
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable", "ES2023"]
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/** @file Configuration for vite. */
|
||||
import * as fsSync from 'node:fs'
|
||||
import * as url from 'node:url'
|
||||
|
||||
import vitePluginYaml from '@modyfi/vite-plugin-yaml'
|
||||
import vitePluginReact from '@vitejs/plugin-react'
|
||||
import * as vite from 'vite'
|
||||
|
||||
import * as common from 'enso-common'
|
||||
import * as appConfig from 'enso-common/src/appConfig'
|
||||
|
||||
// =====================
|
||||
// === Configuration ===
|
||||
// =====================
|
||||
|
||||
const HTTP_STATUS_OK = 200
|
||||
const SERVER_PORT = 8080
|
||||
await appConfig.readEnvironmentFromFile()
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
export default vite.defineConfig({
|
||||
server: { port: SERVER_PORT, headers: Object.fromEntries(common.COOP_COEP_CORP_HEADERS) },
|
||||
plugins: [
|
||||
vitePluginReact({
|
||||
include: '**/*.tsx',
|
||||
babel: { plugins: ['@babel/plugin-syntax-import-attributes'] },
|
||||
}),
|
||||
vitePluginYaml(),
|
||||
serveFavicon(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'#': url.fileURLToPath(new URL('./src', import.meta.url)),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
rollupOptions: {
|
||||
input: {
|
||||
main: url.fileURLToPath(new URL('./index.html', import.meta.url)),
|
||||
'404': url.fileURLToPath(new URL('./404.html', import.meta.url)),
|
||||
},
|
||||
},
|
||||
},
|
||||
define: {
|
||||
// The sole hardcoded usage of `global` in aws-amplify.
|
||||
'global.TYPED_ARRAY_SUPPORT': JSON.stringify(true),
|
||||
...appConfig.getDefines(),
|
||||
},
|
||||
})
|
||||
|
||||
/** A plugin to serve a favicon, in development mode only. */
|
||||
function serveFavicon(): vite.Plugin {
|
||||
const favicon = fsSync.readFileSync(url.fileURLToPath(new URL('./favicon.ico', import.meta.url)))
|
||||
const headers: HeadersInit = [
|
||||
['Content-Length', String(favicon.length)],
|
||||
['Content-Type', 'image/png'],
|
||||
...common.COOP_COEP_CORP_HEADERS,
|
||||
]
|
||||
return {
|
||||
name: 'serve-favicon',
|
||||
configureServer: (server) => {
|
||||
server.middlewares.use((req, res, next) => {
|
||||
if (req.url === '/favicon.ico') {
|
||||
res.writeHead(HTTP_STATUS_OK, headers).end(favicon)
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/** @file Configuration for vitest. */
|
||||
import * as url from 'node:url'
|
||||
|
||||
import * as vitestConfig from 'vitest/config'
|
||||
|
||||
import * as appConfig from 'enso-common/src/appConfig'
|
||||
|
||||
appConfig.loadTestEnvironmentVariables()
|
||||
// @ts-expect-error This is required, otherwise importing node modules is broken.
|
||||
// This is required for `datalinkSchema.test.ts`.
|
||||
process.env.NODE_ENV = 'development'
|
||||
|
||||
const VITE_CONFIG = (await import('./vite.config')).default
|
||||
|
||||
export default vitestConfig.mergeConfig(
|
||||
VITE_CONFIG,
|
||||
vitestConfig.defineConfig({
|
||||
test: {
|
||||
environment: 'jsdom',
|
||||
exclude: [...vitestConfig.configDefaults.exclude, '**/*.spec.{ts,tsx}'],
|
||||
root: url.fileURLToPath(new URL('./', import.meta.url)),
|
||||
restoreMocks: true,
|
||||
},
|
||||
}),
|
||||
)
|
12
app/gui2/.gitignore → app/gui/.gitignore
vendored
12
app/gui2/.gitignore → app/gui/.gitignore
vendored
@ -8,6 +8,7 @@ node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
mockDist
|
||||
*.local
|
||||
*.tsbuildinfo
|
||||
|
||||
@ -25,12 +26,11 @@ coverage
|
||||
test-results/
|
||||
playwright-report/
|
||||
|
||||
src/util/iconList.json
|
||||
src/util/iconName.ts
|
||||
src/stores/visualization/metadata.json
|
||||
public/font-dejavu/
|
||||
public/font-enso/
|
||||
public/font-mplus1/
|
||||
src/assets/font-dejavu.css
|
||||
src/assets/font-enso.css
|
||||
src/assets/font-mplus1.css
|
||||
src/project-view/assets/font-dejavu.css
|
||||
src/project-view/assets/font-enso.css
|
||||
src/project-view/assets/font-mplus1.css
|
||||
src/project-view/util/iconList.json
|
||||
src/project-view/util/iconName.ts
|
@ -3,7 +3,7 @@ import * as test from '@playwright/test'
|
||||
|
||||
import type * as inputBindings from '#/utilities/inputBindings'
|
||||
|
||||
import { modModifier } from '../actions'
|
||||
import { modModifier } from '.'
|
||||
|
||||
// ====================
|
||||
// === PageCallback ===
|
||||
@ -27,7 +27,8 @@ export interface LocatorCallback {
|
||||
// === BaseActions ===
|
||||
// ===================
|
||||
|
||||
/** The base class from which all `Actions` classes are derived.
|
||||
/**
|
||||
* The base class from which all `Actions` classes are derived.
|
||||
* It contains method common to all `Actions` subclasses.
|
||||
* This is a [`thenable`], so it can be used as if it was a {@link Promise}.
|
||||
*
|
||||
@ -40,14 +41,18 @@ export default class BaseActions implements Promise<void> {
|
||||
private readonly promise = Promise.resolve(),
|
||||
) {}
|
||||
|
||||
/** Get the string name of the class of this instance. Required for this class to implement
|
||||
* {@link Promise}. */
|
||||
/**
|
||||
* Get the string name of the class of this instance. Required for this class to implement
|
||||
* {@link Promise}.
|
||||
*/
|
||||
get [Symbol.toStringTag]() {
|
||||
return this.constructor.name
|
||||
}
|
||||
|
||||
/** Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
|
||||
* on all other platforms. */
|
||||
/**
|
||||
* Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
|
||||
* on all other platforms.
|
||||
*/
|
||||
static press(page: test.Page, keyOrShortcut: string): Promise<void> {
|
||||
return test.test.step(`Press '${keyOrShortcut}'`, async () => {
|
||||
if (/\bMod\b|\bDelete\b/.test(keyOrShortcut)) {
|
||||
@ -77,18 +82,22 @@ export default class BaseActions implements Promise<void> {
|
||||
return await this.promise.then(onfulfilled, onrejected)
|
||||
}
|
||||
|
||||
/** Proxies the `catch` method of the internal {@link Promise}.
|
||||
/**
|
||||
* Proxies the `catch` method of the internal {@link Promise}.
|
||||
* This method is not required for this to be a `thenable`, but it is still useful
|
||||
* to treat this class as a {@link Promise}. */
|
||||
* to treat this class as a {@link Promise}.
|
||||
*/
|
||||
// The following types are copied almost verbatim from the type definitions for `Promise`.
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
async catch<T>(onrejected?: ((reason: unknown) => PromiseLike<T> | T) | null | undefined) {
|
||||
return await this.promise.catch(onrejected)
|
||||
}
|
||||
|
||||
/** Proxies the `catch` method of the internal {@link Promise}.
|
||||
/**
|
||||
* Proxies the `catch` method of the internal {@link Promise}.
|
||||
* This method is not required for this to be a `thenable`, but it is still useful
|
||||
* to treat this class as a {@link Promise}. */
|
||||
* to treat this class as a {@link Promise}.
|
||||
*/
|
||||
async finally(onfinally?: (() => void) | null | undefined): Promise<void> {
|
||||
await this.promise.finally(onfinally)
|
||||
}
|
||||
@ -101,9 +110,11 @@ export default class BaseActions implements Promise<void> {
|
||||
return new clazz(this.page, this.promise, ...args)
|
||||
}
|
||||
|
||||
/** Perform an action on the current page. This should generally be avoided in favor of using
|
||||
/**
|
||||
* Perform an action on the current page. This should generally be avoided in favor of using
|
||||
* specific methods; this is more or less an escape hatch used ONLY when the methods do not
|
||||
* support desired functionality. */
|
||||
* support desired functionality.
|
||||
*/
|
||||
do(callback: PageCallback): this {
|
||||
// @ts-expect-error This is SAFE, but only when the constructor of this class has the exact
|
||||
// same parameters as `BaseActions`.
|
||||
@ -119,8 +130,10 @@ export default class BaseActions implements Promise<void> {
|
||||
return this.do(() => test.test.step(name, () => callback(this.page)))
|
||||
}
|
||||
|
||||
/** Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
|
||||
* on all other platforms. */
|
||||
/**
|
||||
* Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
|
||||
* on all other platforms.
|
||||
*/
|
||||
press<Key extends string>(keyOrShortcut: inputBindings.AutocompleteKeybind<Key>) {
|
||||
return this.do((page) => BaseActions.press(page, keyOrShortcut))
|
||||
}
|
||||
@ -157,8 +170,10 @@ export default class BaseActions implements Promise<void> {
|
||||
})
|
||||
}
|
||||
|
||||
/** Expect an input to have an error (or no error if the expected value is `null`).
|
||||
* If the expected value is `undefined`, the assertion is skipped. */
|
||||
/**
|
||||
* Expect an input to have an error (or no error if the expected value is `null`).
|
||||
* If the expected value is `undefined`, the assertion is skipped.
|
||||
*/
|
||||
expectInputError(testId: string, description: string, expected: string | null | undefined) {
|
||||
if (expected === undefined) {
|
||||
return this
|
@ -12,7 +12,7 @@ import {
|
||||
locateSecretNameInput,
|
||||
locateSecretValueInput,
|
||||
TEXT,
|
||||
} from '../actions'
|
||||
} from '.'
|
||||
import type * as baseActions from './BaseActions'
|
||||
import * as contextMenuActions from './contextMenuActions'
|
||||
import EditorPageActions from './EditorPageActions'
|
||||
@ -120,8 +120,10 @@ export default class DrivePageActions extends PageActions {
|
||||
locateAssetRows(page).nth(index).click({ position: ASSET_ROW_SAFE_POSITION }),
|
||||
)
|
||||
},
|
||||
/** Right click a specific row to bring up its context menu, or the context menu for multiple
|
||||
* assets when right clicking on a selected asset when multiple assets are selected. */
|
||||
/**
|
||||
* Right click a specific row to bring up its context menu, or the context menu for multiple
|
||||
* assets when right clicking on a selected asset when multiple assets are selected.
|
||||
*/
|
||||
rightClickRow(index: number) {
|
||||
return self.step(`Right click drive table row #${index}`, (page) =>
|
||||
locateAssetRows(page)
|
||||
@ -164,8 +166,10 @@ export default class DrivePageActions extends PageActions {
|
||||
}),
|
||||
)
|
||||
},
|
||||
/** A test assertion to confirm that there is only one row visible, and that row is the
|
||||
* placeholder row displayed when there are no assets to show. */
|
||||
/**
|
||||
* A test assertion to confirm that there is only one row visible, and that row is the
|
||||
* placeholder row displayed when there are no assets to show.
|
||||
*/
|
||||
expectPlaceholderRow() {
|
||||
return self.step('Expect placeholder row', async (page) => {
|
||||
await test.expect(locateAssetRows(page)).toHaveCount(0)
|
||||
@ -174,8 +178,10 @@ export default class DrivePageActions extends PageActions {
|
||||
await test.expect(nonAssetRows).toHaveText(/This folder is empty/)
|
||||
})
|
||||
},
|
||||
/** A test assertion to confirm that there is only one row visible, and that row is the
|
||||
* placeholder row displayed when there are no assets in Trash. */
|
||||
/**
|
||||
* A test assertion to confirm that there is only one row visible, and that row is the
|
||||
* placeholder row displayed when there are no assets in Trash.
|
||||
*/
|
||||
expectTrashPlaceholderRow() {
|
||||
return self.step('Expect trash placeholder row', async (page) => {
|
||||
await test.expect(locateAssetRows(page)).toHaveCount(0)
|
@ -1,7 +1,7 @@
|
||||
/** @file Available actions for the login page. */
|
||||
import * as test from '@playwright/test'
|
||||
|
||||
import { TEXT, VALID_EMAIL } from '../actions'
|
||||
import { TEXT, VALID_EMAIL } from '.'
|
||||
import BaseActions, { type LocatorCallback } from './BaseActions'
|
||||
import LoginPageActions from './LoginPageActions'
|
||||
|
@ -1,7 +1,7 @@
|
||||
/** @file Available actions for the login page. */
|
||||
import * as test from '@playwright/test'
|
||||
|
||||
import { TEXT, VALID_EMAIL, VALID_PASSWORD, passAgreementsDialog } from '../actions'
|
||||
import { TEXT, VALID_EMAIL, VALID_PASSWORD, passAgreementsDialog } from '.'
|
||||
import BaseActions, { type LocatorCallback } from './BaseActions'
|
||||
import DrivePageActions from './DrivePageActions'
|
||||
import ForgotPasswordPageActions from './ForgotPasswordPageActions'
|
@ -1,7 +1,7 @@
|
||||
/** @file Actions for a "new Data Link" modal. */
|
||||
import type * as test from 'playwright/test'
|
||||
|
||||
import { TEXT } from '../actions'
|
||||
import { TEXT } from '.'
|
||||
import type * as baseActions from './BaseActions'
|
||||
import BaseActions from './BaseActions'
|
||||
import DrivePageActions from './DrivePageActions'
|
@ -1,7 +1,7 @@
|
||||
/** @file Available actions for the login page. */
|
||||
import * as test from '@playwright/test'
|
||||
|
||||
import { TEXT, VALID_EMAIL, VALID_PASSWORD } from '../actions'
|
||||
import { TEXT, VALID_EMAIL, VALID_PASSWORD } from '.'
|
||||
import BaseActions, { type LocatorCallback } from './BaseActions'
|
||||
import LoginPageActions from './LoginPageActions'
|
||||
|
@ -1,5 +1,5 @@
|
||||
/** @file Actions for the fourth step of the "setup" page. */
|
||||
import { TEXT } from '../actions'
|
||||
import { TEXT } from '.'
|
||||
import BaseActions from './BaseActions'
|
||||
import DrivePageActions from './DrivePageActions'
|
||||
|
@ -1,5 +1,5 @@
|
||||
/** @file Actions for the third step of the "setup" page. */
|
||||
import { TEXT } from '../actions'
|
||||
import { TEXT } from '.'
|
||||
import BaseActions from './BaseActions'
|
||||
import SetupTeamPageActions from './SetupTeamPageActions'
|
||||
|
@ -1,5 +1,5 @@
|
||||
/** @file Actions for the third step of the "setup" page. */
|
||||
import { TEXT } from '../actions'
|
||||
import { TEXT } from '.'
|
||||
import BaseActions from './BaseActions'
|
||||
import SetupInvitePageActions from './SetupInvitePageActions'
|
||||
|
@ -1,7 +1,7 @@
|
||||
/** @file Actions for the second step of the "setup" page. */
|
||||
import { PLAN_TO_UPGRADE_LABEL_ID } from '#/modules/payments/constants'
|
||||
import { Plan } from 'enso-common/src/services/Backend'
|
||||
import { TEXT } from '../actions'
|
||||
import { TEXT } from '.'
|
||||
import BaseActions from './BaseActions'
|
||||
import SetupDonePageActions from './SetupDonePageActions'
|
||||
import SetupOrganizationPageActions from './SetupOrganizationPageActions'
|
@ -1,5 +1,5 @@
|
||||
/** @file Actions for the "setup" page. */
|
||||
import { TEXT } from '../actions'
|
||||
import { TEXT } from '.'
|
||||
import BaseActions from './BaseActions'
|
||||
import SetupDonePageActions from './SetupDonePageActions'
|
||||
|
@ -1,5 +1,5 @@
|
||||
/** @file Actions for the "setup" page. */
|
||||
import { TEXT } from '../actions'
|
||||
import { TEXT } from '.'
|
||||
import BaseActions from './BaseActions'
|
||||
import SetupPlanPageActions from './SetupPlanPageActions'
|
||||
|
@ -1,5 +1,5 @@
|
||||
/** @file Actions for the "home" page. */
|
||||
import * as actions from '../actions'
|
||||
import * as actions from '.'
|
||||
import BaseActions from './BaseActions'
|
||||
import DrivePageActions from './DrivePageActions'
|
||||
import EditorPageActions from './EditorPageActions'
|
@ -1,5 +1,5 @@
|
||||
/** @file Actions for the context menu. */
|
||||
import { TEXT } from '../actions'
|
||||
import { TEXT } from '.'
|
||||
import type * as baseActions from './BaseActions'
|
||||
import type BaseActions from './BaseActions'
|
||||
import EditorPageActions from './EditorPageActions'
|
@ -4,9 +4,9 @@ import * as test from '@playwright/test'
|
||||
|
||||
import { TEXTS } from 'enso-common/src/text'
|
||||
|
||||
import DrivePageActions from './actions/DrivePageActions'
|
||||
import LoginPageActions from './actions/LoginPageActions'
|
||||
import * as apiModule from './api'
|
||||
import * as apiModule from '../api'
|
||||
import DrivePageActions from './DrivePageActions'
|
||||
import LoginPageActions from './LoginPageActions'
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-namespace */
|
||||
|
||||
@ -292,7 +292,7 @@ export function locateSamples(page: test.Locator | test.Page) {
|
||||
/** Find an editor container (if any) on the current page. */
|
||||
export function locateEditor(page: test.Page) {
|
||||
// Test ID of a placeholder editor component used during testing.
|
||||
return page.getByTestId('gui-editor-root')
|
||||
return page.locator('.App')
|
||||
}
|
||||
|
||||
/** Find an assets table (if any) on the current page. */
|
||||
@ -315,16 +315,20 @@ export function locateAssetName(locator: test.Locator) {
|
||||
return locator.locator('> :nth-child(1)')
|
||||
}
|
||||
|
||||
/** Find assets table rows that represent directories that can be expanded (if any)
|
||||
* on the current page. */
|
||||
/**
|
||||
* Find assets table rows that represent directories that can be expanded (if any)
|
||||
* on the current page.
|
||||
*/
|
||||
export function locateExpandableDirectories(page: test.Page) {
|
||||
// The icon is hidden when not hovered so `getByLabel` will not work.
|
||||
// eslint-disable-next-line no-restricted-properties
|
||||
return locateAssetRows(page).filter({ has: page.locator('[aria-label=Expand]') })
|
||||
}
|
||||
|
||||
/** Find assets table rows that represent directories that can be collapsed (if any)
|
||||
* on the current page. */
|
||||
/**
|
||||
* Find assets table rows that represent directories that can be collapsed (if any)
|
||||
* on the current page.
|
||||
*/
|
||||
export function locateCollapsibleDirectories(page: test.Page) {
|
||||
// The icon is hidden when not hovered so `getByLabel` will not work.
|
||||
// eslint-disable-next-line no-restricted-properties
|
||||
@ -390,9 +394,11 @@ export function locateExtraColumns(page: test.Page) {
|
||||
return page.getByTestId('extra-columns')
|
||||
}
|
||||
|
||||
/** Find a root directory dropzone (if any) on the current page.
|
||||
/**
|
||||
* Find a root directory dropzone (if any) on the current page.
|
||||
* This is the empty space below the assets table, if it doesn't take up the whole screen
|
||||
* vertically. */
|
||||
* vertically.
|
||||
*/
|
||||
export function locateRootDirectoryDropzone(page: test.Page) {
|
||||
// This has no identifying features.
|
||||
return page.getByTestId('root-directory-dropzone')
|
||||
@ -591,9 +597,11 @@ export namespace settings {
|
||||
// === Visual layout utilities ===
|
||||
// ===============================
|
||||
|
||||
/** Get the left side of the bounding box of an asset row. The locator MUST be for an asset row.
|
||||
/**
|
||||
* Get the left side of the bounding box of an asset row. The locator MUST be for an asset row.
|
||||
* DO NOT assume the left side of the outer container will change. This means that it is NOT SAFE
|
||||
* to do anything with the returned values other than comparing them. */
|
||||
* to do anything with the returned values other than comparing them.
|
||||
*/
|
||||
export function getAssetRowLeftPx(locator: test.Locator) {
|
||||
return locator.evaluate((el) => el.children[0]?.children[0]?.getBoundingClientRect().left ?? 0)
|
||||
}
|
||||
@ -688,8 +696,10 @@ export async function modModifier(page: test.Page) {
|
||||
return /\bMac OS\b/i.test(userAgent) ? 'Meta' : 'Control'
|
||||
}
|
||||
|
||||
/** Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
|
||||
* on all other platforms. */
|
||||
/**
|
||||
* Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
|
||||
* on all other platforms.
|
||||
*/
|
||||
export async function press(page: test.Page, keyOrShortcut: string) {
|
||||
await test.test.step(`Press '${keyOrShortcut}'`, async () => {
|
||||
if (/\bMod\b|\bDelete\b/.test(keyOrShortcut)) {
|
||||
@ -837,8 +847,10 @@ export function mockAllAndLogin({ page, setupAPI }: MockParams) {
|
||||
.do((thePage) => login({ page: thePage, setupAPI }))
|
||||
}
|
||||
|
||||
/** Set up all mocks, and log in with dummy credentials.
|
||||
* @deprecated Prefer {@link mockAllAndLogin}. */
|
||||
/**
|
||||
* Set up all mocks, and log in with dummy credentials.
|
||||
* @deprecated Prefer {@link mockAllAndLogin}.
|
||||
*/
|
||||
// This syntax is required for Playwright to work properly.
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
export async function mockAllAndLoginAndExposeAPI({ page, setupAPI }: MockParams) {
|
@ -1,5 +1,5 @@
|
||||
/** @file An action to open the User Menu. */
|
||||
import { TEXT } from '../actions'
|
||||
import { TEXT } from '.'
|
||||
import type BaseActions from './BaseActions'
|
||||
import type { PageCallback } from './BaseActions'
|
||||
|
@ -58,7 +58,7 @@ export interface SetupAPI {
|
||||
}
|
||||
|
||||
/** The return type of {@link mockApi}. */
|
||||
export interface MockApi extends Awaited<ReturnType<typeof mockApiInternal>> {}
|
||||
export type MockApi = Awaited<ReturnType<typeof mockApiInternal>>
|
||||
|
||||
// This is a function, even though it does not contain function syntax.
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
@ -582,7 +582,7 @@ async function mockApiInternal({ page, setupAPI }: MockParams) {
|
||||
'Development' satisfies `${backend.VersionLifecycle.development}` as backend.VersionLifecycle.development,
|
||||
value: '2023.2.1-dev',
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention, no-restricted-syntax
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention, camelcase, no-restricted-syntax
|
||||
version_type: (new URL(request.url()).searchParams.get('version_type') ??
|
||||
'') as backend.VersionType,
|
||||
} satisfies backend.Version,
|
||||
@ -603,9 +603,9 @@ async function mockApiInternal({ page, setupAPI }: MockParams) {
|
||||
name: 'example project name',
|
||||
state: project.projectState,
|
||||
packageName: 'Project_root',
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention, camelcase
|
||||
ide_version: null,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention, camelcase
|
||||
engine_version: {
|
||||
value: '2023.2.1-nightly.2023.9.29',
|
||||
lifecycle: backend.VersionLifecycle.development,
|
@ -9,12 +9,7 @@ import type {
|
||||
import { createContext, useContext, useEffect, useState } from 'react'
|
||||
|
||||
/** */
|
||||
type ElementsContextValue_ = Parameters<Parameters<typeof StripeElementConsumer>[0]['children']>[0]
|
||||
|
||||
/** */
|
||||
interface ElementsContextValue extends ElementsContextValue_ {
|
||||
//
|
||||
}
|
||||
type ElementsContextValue = Parameters<Parameters<typeof StripeElementConsumer>[0]['children']>[0]
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const ElementsContext = createContext<ElementsContextValue>(null!)
|
@ -10,7 +10,7 @@ export const loadStripe = (): Promise<Stripe> =>
|
||||
paymentMethod: {
|
||||
id: '',
|
||||
object: 'payment_method',
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention, camelcase
|
||||
billing_details: {
|
||||
address: null,
|
||||
email: null,
|
@ -46,7 +46,7 @@ test('Using breadcrumbs to navigate', async ({ page }) => {
|
||||
await expectInsideMain(page)
|
||||
// Breadcrumbs still have all the crumbs, but the last two are dimmed.
|
||||
await expect(locate.navBreadcrumb(page)).toHaveText(['Mock Project', 'func1', 'func2'])
|
||||
await expect(locate.navBreadcrumb(page, (f) => f.class('inactive'))).toHaveText([
|
||||
await expect(locate.navBreadcrumb(page).and(page.locator('.inactive'))).toHaveText([
|
||||
'func1',
|
||||
'func2',
|
||||
])
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user