web: unify unit and end-to-end tests (#11598)

* Just cleaning up.

* web: removing sonarjs from yet another branch.

* web: everything except the tests are up-to-date.  There was a lot, it turns out, we simply weren't using.

* web: update package.json to support WebdriverIO 9

This commit:

- Upgrades to WebdriverIO 9.1.2
- Resets our `devDependencies` collection to remove all imports that we either were not using or
  were duplicates of existing dependencies:
  - *Babel*, of all things
  - Storybook addon css user preferences, now native to Storybook 8
  - SonarJS, *again*, sigh.
  - React

- Fixes a bug where ESLint would report missing features in our build scripts
- Fixes a bug where Wdio might not reach a headless browser before timeout
- Replaces Rollup's CSSLit with Vite's CSSLit, which actually works without hacks, for testing.
- Moves the package-lock scanner to its own script, with better reporting and tool verification,
  which also cleans up the package.lock file a little.

* web: unify unit and end-to-end tests

This commit builds on the Upgrade to WebdriverIO 9.1 and provides *two* variants of the wdio.conf
file: One in `browser` mode, so that standalone component tests are uploaded to the browser and run
independently, and one in `local` mode that allows the Webdriver-DOM framework to run end-to-end
tests.  This means that both Component and End-to-End tests use the same drivers, same framework,
and same versions, and all tests for the WebUI are contained in this folder.

* Prettier just opinionatin' all over the place.

* Eslint bein' disagreeable.

* Tests embedded like ticks.

* Someday I'll get prettier to agree with my IDE.

* Re-ran the installation with resolutions enforced.

* web: fix type errors in tests

Typechecking the tests is pretty messy, first because WebdriverIO passes around a lot of `ChainablePromise` objects, which TSC does not know
how to resolve to their final form after a full `await`, and second because I used a lot of metaprogramming to provide getters for the
different kinds of subtypes (here: providers) that we are targeting.  So there are a lot of compromises here, none of which make me
spectacularly happy, but they're all well-commented, so there's that.

* But I am done with you, orc.

* Fixed broken comment.
This commit is contained in:
Ken Sternberg
2024-10-03 11:40:47 -07:00
committed by GitHub
parent dec8cfbb39
commit 22a77a7fc4
41 changed files with 283 additions and 16012 deletions

View File

@ -23,7 +23,6 @@ updates:
- package-ecosystem: npm
directories:
- "/web"
- "/tests/wdio"
- "/web/sfe"
schedule:
interval: daily

View File

@ -24,17 +24,11 @@ jobs:
- prettier-check
project:
- web
- tests/wdio
include:
- command: tsc
project: web
- command: lit-analyse
project: web
exclude:
- command: lint:lockfile
project: tests/wdio
- command: tsc
project: tests/wdio
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4

109
tests/wdio/.gitignore vendored
View File

@ -1,109 +0,0 @@
# Created by https://www.gitignore.io/api/node
# Edit at https://www.gitignore.io/?templates=node
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
dist
# Uncomment the public line if your project uses Gatsby
# https://nextjs.org/blog/next-9-1#public-directory-support
# https://create-react-app.dev/docs/using-the-public-folder/#docsNav
# public
# Storybook build outputs
.out
.storybook-out
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# Temporary folders
tmp/
temp/
# End of https://www.gitignore.io/api/node

View File

@ -1,7 +0,0 @@
# don't ever lint node_modules
node_modules
# don't lint nyc coverage output
coverage
# Prettier breaks the tsconfig file
tsconfig.json
.eslintrc.json

View File

@ -1,22 +0,0 @@
{
"arrowParens": "always",
"bracketSpacing": true,
"embeddedLanguageFormatting": "auto",
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"jsxSingleQuote": false,
"printWidth": 100,
"proseWrap": "preserve",
"quoteProps": "consistent",
"requirePragma": false,
"semi": true,
"singleQuote": false,
"tabWidth": 4,
"trailingComma": "all",
"useTabs": false,
"vueIndentScriptAndStyle": false,
"plugins": ["@trivago/prettier-plugin-sort-imports"],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true,
"importOrderParserPlugins": ["typescript", "classProperties", "decorators-legacy"]
}

View File

@ -1,41 +0,0 @@
.PHONY: help precommit admin-user test-good-login test-bad-login
help: ## Show this help
@echo "\nSpecify a command. The choices are:\n"
@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[0;36m%-20s\033[m %s\n", $$1, $$2}'
@echo ""
ROOT := $(shell git rev-parse --show-toplevel 2> /dev/null)
WDIO = npm run wdio
SPEC = $(WDIO) -- --logLevel warn --spec ./test/specs
LOCAL_BLUEPRINTS=$(ROOT)/blueprints/local
node_modules: ## Runs `npm install` to prepare this feature
npm ci
precommit: node_modules ## Run the precommit: spell check all comments, eslint with sonarJS, prettier-write
npm run precommit
# Actual tests are down below:
$(ROOT)/blueprints/local/admin-user.yaml:
mkdir -p $(LOCAL_BLUEPRINTS)
cp ./blueprints/admin-user.yaml $(LOCAL_BLUEPRINTS)
cd $(ROOT) && ak apply_blueprint local/admin-user.yaml
admin-user: $(ROOT)/blueprints/local/admin-user.yaml
test-good-login: node_modules admin-user ## Test that we can log into the server. Requires a running instance of the server.
$(SPEC)/good-login.ts
test-bad-login: node_modules admin-user ## Test that bad usernames and passwords create appropriate error messages
$(SPEC)/bad-logins.ts
test-application-wizard: node_modules admin-user ## Test that the application wizard works as expected
$(SPEC)/new-application-by-wizard.ts

View File

@ -1,16 +0,0 @@
version: 1
entries:
- attrs:
email: test-admin@goauthentik.io
is_active: true
name: authentik Default Admin
password: test-runner
path: users
type: internal
groups:
- !Find [authentik_core.group, [name, "authentik Admins"]]
conditions: []
identifiers:
username: akadmin
model: authentik_core.user
state: present

View File

@ -1,84 +0,0 @@
import eslint from "@eslint/js";
import tsparser from "@typescript-eslint/parser";
import litconf from "eslint-plugin-lit";
import wcconf from "eslint-plugin-wc";
import globals from "globals";
import tseslint from "typescript-eslint";
export default [
// You would not believe how much this change has frustrated users: ["if an ignores key is used
// without any other keys in the configuration object, then the patterns act as global
// ignores"](https://eslint.org/docs/latest/use/configure/ignore)
{
ignores: [
"dist/",
// don't lint the cache
".wireit/",
// let packages have their own configurations
"packages/",
// don't ever lint node_modules
"node_modules/",
".storybook/*",
// don't lint build output (make sure it's set to your correct build folder name)
// don't lint nyc coverage output
"coverage/",
"src/locale-codes.ts",
"storybook-static/",
"src/locales/",
],
},
eslint.configs.recommended,
wcconf.configs["flat/recommended"],
litconf.configs["flat/recommended"],
...tseslint.configs.recommended,
{
languageOptions: {
parser: tsparser,
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
},
},
files: ["src/**"],
rules: {
"no-unused-vars": "off",
"no-console": ["error", { allow: ["debug", "warn", "error"] }],
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
},
},
{
languageOptions: {
parser: tsparser,
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
},
globals: {
...globals.nodeBuiltin,
},
},
files: ["scripts/*.mjs", "*.ts", "*.mjs"],
rules: {
"no-unused-vars": "off",
// We WANT our scripts to output to the console!
"no-console": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
},
},
];

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +0,0 @@
{
"name": "@goauthentik/web-tests",
"dependencies": {
"chromedriver": "^129.0.2",
"lockfile-lint": "^4.14.0",
"syncpack": "^13.0.0"
},
"devDependencies": {
"@eslint/js": "^9.11.1",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/mocha": "^10.0.8",
"@typescript-eslint/eslint-plugin": "^8.8.0",
"@typescript-eslint/parser": "^8.8.0",
"@wdio/cli": "^9.1.2",
"@wdio/local-runner": "^9.1.2",
"@wdio/mocha-framework": "^9.1.2",
"@wdio/spec-reporter": "^9.1.2",
"eslint-plugin-lit": "^1.14.0",
"eslint-plugin-sonarjs": "^2.0.3",
"eslint-plugin-wc": "^2.1.0",
"eslint": "^9.11.1",
"npm-run-all": "^4.1.5",
"prettier": "^3.3.3",
"typescript-eslint": "^8.8.0",
"typescript": "^5.6.2",
"wdio-wait-for": "^3.0.11"
},
"engines": {
"node": ">=20"
},
"private": true,
"scripts": {
"lint": "eslint . --max-warnings 0 --fix",
"lint:lockfile": "lockfile-lint --path package.json --type npm --allowed-hosts npm --validate-https",
"lint:package": "syncpack format -i ' '",
"lint:precommit": "eslint --max-warnings 0 --config ./.eslintrc.precommit.json $(git status --porcelain . | grep '^[AM?][M?]' | cut -d'/' -f3- | grep -E '\\.(ts|js|tsx|jsx)$')",
"lint:spelling": "codespell -D - -D $(git rev-parse --show-toplevel 2> /dev/null)/.github/codespell-dictionary.txt -I $(git rev-parse --show-toplevel 2> /dev/null)/.github/codespell-words.txt ./test -s",
"precommit": "run-s lint:precommit lint:spelling prettier",
"prettier": "prettier --write .",
"prettier-check": "prettier --check .",
"wdio": "wdio run ./wdio.conf.ts"
},
"type": "module"
}

254
web/package-lock.json generated
View File

@ -75,11 +75,13 @@
"@types/mocha": "^10.0.8",
"@types/node": "^22.7.4",
"@types/showdown": "^2.0.6",
"@typescript-eslint/eslint-plugin": "^8.8.0",
"@typescript-eslint/parser": "^8.8.0",
"@wdio/browser-runner": "^9.1.2",
"@wdio/cli": "^9.1.2",
"@wdio/spec-reporter": "^9.1.2",
"chokidar": "^4.0.1",
"chromedriver": "^129.0.2",
"esbuild": "^0.24.0",
"eslint": "^9.11.1",
"eslint-plugin-lit": "^1.15.0",
@ -3459,102 +3461,102 @@
"dev": true
},
"node_modules/@sentry-internal/browser-utils": {
"version": "8.33.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.33.0.tgz",
"integrity": "sha512-zwjmD+XI3pgxxiqKGLXYDGSd+zfO7az9zzbLn1le8Vv9cRL2lZyMLcwiwEaTpwz3B0pPONeDZMT8+bzMGRs8zw==",
"version": "8.33.1",
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.33.1.tgz",
"integrity": "sha512-TW6/r+Gl5jiXv54iK1xZ3mlVgTS/jaBp4vcQ0xGMdgiQ3WchEPcFSeYovL+YHT3tSud0GZqVtDQCz+5i76puqA==",
"dependencies": {
"@sentry/core": "8.33.0",
"@sentry/types": "8.33.0",
"@sentry/utils": "8.33.0"
"@sentry/core": "8.33.1",
"@sentry/types": "8.33.1",
"@sentry/utils": "8.33.1"
},
"engines": {
"node": ">=14.18"
}
},
"node_modules/@sentry-internal/feedback": {
"version": "8.33.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.33.0.tgz",
"integrity": "sha512-KSW/aiNgmJc8PDl2NsM+ONvGure4tPaluj7O1Nw+947Dh8W6CJnQ9srB7xPyoYYWyQW8Hyl1vzxY9W0J+fjlhA==",
"version": "8.33.1",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.33.1.tgz",
"integrity": "sha512-qauMRTm3qDaLqZ3ibI03cj4gLF40y0ij65nj+cns6iWxGCtPrO8tjvXFWuQsE7Aye9dGMnBgmv7uN+NTUtC3RA==",
"dependencies": {
"@sentry/core": "8.33.0",
"@sentry/types": "8.33.0",
"@sentry/utils": "8.33.0"
"@sentry/core": "8.33.1",
"@sentry/types": "8.33.1",
"@sentry/utils": "8.33.1"
},
"engines": {
"node": ">=14.18"
}
},
"node_modules/@sentry-internal/replay": {
"version": "8.33.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.33.0.tgz",
"integrity": "sha512-GFBaDA4yhlEf3wTXOVXnJVG/diuKxeqZuXcuhsAwJb+YcFR0NhgsRn3wIGuYOZZF8GBXzx9PFnb9yIuFgx5Nbw==",
"version": "8.33.1",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.33.1.tgz",
"integrity": "sha512-fm4coIOjmanU29NOVN9MyaP4fUCOYytbtFqVSKRFNZQ/xAgNeySiBIbUd6IjujMmnOk9bY0WEUMcdm3Uotjdog==",
"dependencies": {
"@sentry-internal/browser-utils": "8.33.0",
"@sentry/core": "8.33.0",
"@sentry/types": "8.33.0",
"@sentry/utils": "8.33.0"
"@sentry-internal/browser-utils": "8.33.1",
"@sentry/core": "8.33.1",
"@sentry/types": "8.33.1",
"@sentry/utils": "8.33.1"
},
"engines": {
"node": ">=14.18"
}
},
"node_modules/@sentry-internal/replay-canvas": {
"version": "8.33.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.33.0.tgz",
"integrity": "sha512-9fEhMP+gQYQrtn/SQd1Vd7U7emTSGBpLKc5h5f0iV0yDmjYAhNVbq4RgPTYAgnBEcdVo3qgboL6UIz9Dv+dYRQ==",
"version": "8.33.1",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.33.1.tgz",
"integrity": "sha512-nsxTFTPCT10Ty/v6+AiST3+yotGP1sUb8xqfKB9fPnS1hZHFryp0NnEls7xFjBsBbZPU1GpFkzrk/E6JFzixDQ==",
"dependencies": {
"@sentry-internal/replay": "8.33.0",
"@sentry/core": "8.33.0",
"@sentry/types": "8.33.0",
"@sentry/utils": "8.33.0"
"@sentry-internal/replay": "8.33.1",
"@sentry/core": "8.33.1",
"@sentry/types": "8.33.1",
"@sentry/utils": "8.33.1"
},
"engines": {
"node": ">=14.18"
}
},
"node_modules/@sentry/browser": {
"version": "8.33.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.33.0.tgz",
"integrity": "sha512-qu/g20ZskywEU8BWc4Fts1kXFFBtw1vS+XvPq7Ta9zCeRG5dlXhhYDVQ4/v4nAL/cs0o6aLCq73m109CFF0Kig==",
"version": "8.33.1",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.33.1.tgz",
"integrity": "sha512-c6zI/igexkLwZuGk+u8Rj26ChjxGgkhe6ZbKFsXCYaKAp5ep5X7HQRkkqgbxApiqlC0LduHdd/ymzh139JLg8w==",
"dependencies": {
"@sentry-internal/browser-utils": "8.33.0",
"@sentry-internal/feedback": "8.33.0",
"@sentry-internal/replay": "8.33.0",
"@sentry-internal/replay-canvas": "8.33.0",
"@sentry/core": "8.33.0",
"@sentry/types": "8.33.0",
"@sentry/utils": "8.33.0"
"@sentry-internal/browser-utils": "8.33.1",
"@sentry-internal/feedback": "8.33.1",
"@sentry-internal/replay": "8.33.1",
"@sentry-internal/replay-canvas": "8.33.1",
"@sentry/core": "8.33.1",
"@sentry/types": "8.33.1",
"@sentry/utils": "8.33.1"
},
"engines": {
"node": ">=14.18"
}
},
"node_modules/@sentry/core": {
"version": "8.33.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.33.0.tgz",
"integrity": "sha512-618PQGHQLBVCpAq1s+e/rpIUaLUnj19IPUgn97rUGXLLna8ETIAoyQoG70wz4q9niw4Z4GlS5kZNrael2O3+2w==",
"version": "8.33.1",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.33.1.tgz",
"integrity": "sha512-3SS41suXLFzxL3OQvTMZ6q92ZapELVq2l2SoWlZopcamWhog2Ru0dp2vkunq97kFHb2TzKRTlFH4+4gbT8SJug==",
"dependencies": {
"@sentry/types": "8.33.0",
"@sentry/utils": "8.33.0"
"@sentry/types": "8.33.1",
"@sentry/utils": "8.33.1"
},
"engines": {
"node": ">=14.18"
}
},
"node_modules/@sentry/types": {
"version": "8.33.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.33.0.tgz",
"integrity": "sha512-V/A+72ZdnfGtXeXIpz1kUo3LRdq3WKEYYFUR2RKpCdPh9yeOrHq6u/rmzTWx49+om0yhZN+JhVoxDzt75UoFRg==",
"version": "8.33.1",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.33.1.tgz",
"integrity": "sha512-GjoAMvwtpIemoF/IiwZ7A60g4nQv3qwzR21GvJqDVUoKD0e8pv9OLX+HyXoUat4wEDGSuDUcUyUKD2G+od73QA==",
"engines": {
"node": ">=14.18"
}
},
"node_modules/@sentry/utils": {
"version": "8.33.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.33.0.tgz",
"integrity": "sha512-TdwtGdevJij2wq2x/hDUr+x5TXt47ZhWxZ8zluai/lnIDTUB3Xs/L9yHtj1J+H9hr8obkMASE9IanUrWXzrP6Q==",
"version": "8.33.1",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.33.1.tgz",
"integrity": "sha512-uzuYpiiJuFY3N4WNHMBWUQX5oNv2t/TbG0OHRp3Rr7yeu+HSfD542TIp9/gMZ+G0Cxd8AmVO3wkKIFbk0TL4Qg==",
"dependencies": {
"@sentry/types": "8.33.0"
"@sentry/types": "8.33.1"
},
"engines": {
"node": ">=14.18"
@ -5446,6 +5448,12 @@
"node": ">=10"
}
},
"node_modules/@testim/chrome-version": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.4.tgz",
"integrity": "sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g==",
"dev": true
},
"node_modules/@tokenizer/token": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
@ -5774,9 +5782,9 @@
}
},
"node_modules/@types/lodash": {
"version": "4.17.9",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.9.tgz",
"integrity": "sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w==",
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-YpS0zzoduEhuOWjAotS6A5AVCva7X4lVlYLF0FYHAY9sdraBfnatttHItlWeZdGhuEkf+OzMNg2ZYAx8t+52uQ==",
"dev": true
},
"node_modules/@types/mdx": {
@ -8611,6 +8619,28 @@
"node": ">=10"
}
},
"node_modules/chromedriver": {
"version": "129.0.2",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-129.0.2.tgz",
"integrity": "sha512-rUEFCJAmAwOdFfaDFtveT97fFeA7NOxlkgyPyN+G09Ws4qGW39aLDxMQBbS9cxQQHhTihqZZobgF5CLVYXnmGA==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
"@testim/chrome-version": "^1.1.4",
"axios": "^1.7.4",
"compare-versions": "^6.1.0",
"extract-zip": "^2.0.1",
"proxy-agent": "^6.4.0",
"proxy-from-env": "^1.1.0",
"tcp-port-used": "^1.0.2"
},
"bin": {
"chromedriver": "bin/chromedriver"
},
"engines": {
"node": ">=18"
}
},
"node_modules/ci-info": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
@ -8854,6 +8884,12 @@
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
"dev": true
},
"node_modules/compare-versions": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz",
"integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==",
"dev": true
},
"node_modules/compatx": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/compatx/-/compatx-0.1.8.tgz",
@ -9995,9 +10031,9 @@
}
},
"node_modules/dompurify": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz",
"integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ=="
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz",
"integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ=="
},
"node_modules/domutils": {
"version": "3.1.0",
@ -12936,6 +12972,15 @@
"node": ">= 12"
}
},
"node_modules/ip-regex": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz",
"integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@ -13374,6 +13419,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-url": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
"integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==",
"dev": true
},
"node_modules/is-valid-element-name": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-valid-element-name/-/is-valid-element-name-1.0.0.tgz",
@ -13407,6 +13458,20 @@
"node": ">=8"
}
},
"node_modules/is2": {
"version": "2.0.9",
"resolved": "https://registry.npmjs.org/is2/-/is2-2.0.9.tgz",
"integrity": "sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==",
"dev": true,
"dependencies": {
"deep-is": "^0.1.3",
"ip-regex": "^4.1.0",
"is-url": "^1.2.4"
},
"engines": {
"node": ">=v0.10.0"
}
},
"node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
@ -13947,6 +14012,7 @@
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
"dev": true,
"optional": true,
"bin": {
"jiti": "bin/jiti.js"
}
@ -14179,9 +14245,9 @@
}
},
"node_modules/knip": {
"version": "5.30.6",
"resolved": "https://registry.npmjs.org/knip/-/knip-5.30.6.tgz",
"integrity": "sha512-YkcnRVl0N99xZ7eaXE7KlH/4cPTCn6BGuk9KxINEdCMFN3yita2vGBizApy97ZOHgghy8tb589gQ3xvLMFIO4w==",
"version": "5.31.0",
"resolved": "https://registry.npmjs.org/knip/-/knip-5.31.0.tgz",
"integrity": "sha512-4hR+qHx/id7mniCWWUqA4MXwGjYFN75xv3qLmEkl9Hm6eCKAhv0wGP0CyrXKUYxVyDplJQsqQaAlsjuRKYsdPA==",
"dev": true,
"funding": [
{
@ -14203,7 +14269,7 @@
"easy-table": "1.2.0",
"enhanced-resolve": "^5.17.1",
"fast-glob": "^3.3.2",
"jiti": "^1.21.6",
"jiti": "^2.1.0",
"js-yaml": "^4.1.0",
"minimist": "^1.2.8",
"picocolors": "^1.0.0",
@ -14227,6 +14293,15 @@
"typescript": ">=5.0.4"
}
},
"node_modules/knip/node_modules/jiti": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.1.2.tgz",
"integrity": "sha512-cYNjJus5X9J4jLzTaI8rYoIq1k6YySiA1lK4wxSnOrBRXkbVyreZfhoboJhsUmwgU82lpPjj1IoU7Ggrau8r3g==",
"dev": true,
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
},
"node_modules/knip/node_modules/strip-json-comments": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz",
@ -14870,9 +14945,9 @@
}
},
"node_modules/mermaid": {
"version": "11.2.1",
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.2.1.tgz",
"integrity": "sha512-F8TEaLVVyxTUmvKswVFyOkjPrlJA5h5vNR1f7ZnSWSpqxgEZG1hggtn/QCa7znC28bhlcrNh10qYaIiill7q4A==",
"version": "11.3.0",
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.3.0.tgz",
"integrity": "sha512-fFmf2gRXLtlGzug4wpIGN+rQdZ30M8IZEB1D3eZkXNqC7puhqeURBcD/9tbwXsqBO+A6Nzzo3MSSepmnw5xSeg==",
"dependencies": {
"@braintree/sanitize-url": "^7.0.1",
"@iconify/utils": "^2.1.32",
@ -14884,7 +14959,7 @@
"d3-sankey": "^0.12.3",
"dagre-d3-es": "7.0.10",
"dayjs": "^1.11.10",
"dompurify": "^3.0.11",
"dompurify": "^3.0.11 <3.1.7",
"katex": "^0.16.9",
"khroma": "^2.1.0",
"lodash-es": "^4.17.21",
@ -17775,9 +17850,9 @@
}
},
"node_modules/readdirp": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.1.tgz",
"integrity": "sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
"integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
"dev": true,
"engines": {
"node": ">= 14.16.0"
@ -17864,15 +17939,15 @@
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"node_modules/regexp.prototype.flags": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
"integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz",
"integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.6",
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
"es-errors": "^1.3.0",
"set-function-name": "^2.0.1"
"set-function-name": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
@ -19558,6 +19633,39 @@
"node": ">=8"
}
},
"node_modules/tcp-port-used": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz",
"integrity": "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==",
"dev": true,
"dependencies": {
"debug": "4.3.1",
"is2": "^2.0.6"
}
},
"node_modules/tcp-port-used/node_modules/debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/tcp-port-used/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/telejson": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/telejson/-/telejson-7.2.0.tgz",
@ -20778,9 +20886,9 @@
}
},
"node_modules/untyped/node_modules/jiti": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.1.0.tgz",
"integrity": "sha512-Nftp80J8poC3u+93ZxpjstsgfQ5d0o5qyD6yStv32sgnWr74xRxBppEwsUoA/GIdrJpgGRkC1930YkLcAsFdSw==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.1.2.tgz",
"integrity": "sha512-cYNjJus5X9J4jLzTaI8rYoIq1k6YySiA1lK4wxSnOrBRXkbVyreZfhoboJhsUmwgU82lpPjj1IoU7Ggrau8r3g==",
"dev": true,
"optional": true,
"bin": {

View File

@ -63,11 +63,13 @@
"@types/mocha": "^10.0.8",
"@types/node": "^22.7.4",
"@types/showdown": "^2.0.6",
"@typescript-eslint/eslint-plugin": "^8.8.0",
"@typescript-eslint/parser": "^8.8.0",
"@wdio/browser-runner": "^9.1.2",
"@wdio/cli": "^9.1.2",
"@wdio/spec-reporter": "^9.1.2",
"chokidar": "^4.0.1",
"chromedriver": "^129.0.2",
"esbuild": "^0.24.0",
"eslint": "^9.11.1",
"eslint-plugin-lit": "^1.15.0",
@ -130,7 +132,8 @@
"storybook:build": "wireit",
"storybook:build-import-map": "wireit",
"test": "wireit",
"test-watch": "wireit",
"test:e2e:watch": "wireit",
"test:watch": "wireit",
"tsc": "wireit",
"watch": "run-s build-locales esbuild:watch"
},
@ -233,10 +236,14 @@
"lint:imports": {
"command": "knip --config scripts/knip.config.ts"
},
"lint:types:tests": {
"command": "tsc --noEmit -p ./tests"
},
"lint:types": {
"command": "tsc --noEmit -p .",
"dependencies": [
"build-locales"
"build-locales",
"lint:types:tests"
]
},
"lint:lockfile": {
@ -315,7 +322,13 @@
"TS_NODE_PROJECT": "tsconfig.test.json"
}
},
"test-watch": {
"test:e2e:watch": {
"command": "wdio run ./tests/wdio.conf.ts",
"env": {
"TS_NODE_PROJECT": "./tests/tsconfig.test.json"
}
},
"test:watch": {
"command": "wdio run ./wdio.conf.ts",
"env": {
"TS_NODE_PROJECT": "tsconfig.test.json"

View File

@ -1,3 +1,5 @@
import { $ } from "@wdio/globals";
import Page from "../pageobjects/page.js";
export default class AdminPage extends Page {

View File

@ -1,3 +1,5 @@
import { $ } from "@wdio/globals";
import AdminPage from "./admin.page.js";
import ApplicationForm from "./forms/application.form.js";
import ForwardProxyForm from "./forms/forward-proxy.form.js";
@ -7,7 +9,6 @@ import RadiusForm from "./forms/radius.form.js";
import SamlForm from "./forms/saml.form.js";
import ScimForm from "./forms/scim.form.js";
import TransparentProxyForm from "./forms/transparent-proxy.form.js";
import { $ } from "@wdio/globals";
/**
* sub page containing specific selectors and methods for a specific page
@ -40,6 +41,7 @@ class ApplicationWizardView extends AdminPage {
}
async getProviderType(type: string) {
// @ts-expect-error "TSC does not understand the ChainablePromiseElement type at all."
return await this.providerList().$(`input[value="${type}"]`);
}

View File

@ -1,6 +1,7 @@
import AdminPage from "./admin.page.js";
import { $ } from "@wdio/globals";
import AdminPage from "./admin.page.js";
/**
* sub page containing specific selectors and methods for a specific page
*/

View File

@ -1,6 +1,7 @@
import Page from "../page.js";
import { $ } from "@wdio/globals";
import Page from "../page.js";
export class ApplicationForm extends Page {
async name() {
return await $('ak-text-input[name="name"]').$("input");

View File

@ -1,6 +1,7 @@
import Page from "../page.js";
import { $ } from "@wdio/globals";
import Page from "../page.js";
export class ForwardProxyForm extends Page {
async setAuthorizationFlow(selector: string) {
await this.searchSelect(

View File

@ -1,6 +1,7 @@
import Page from "../page.js";
import { $ } from "@wdio/globals";
import Page from "../page.js";
export class OauthForm extends Page {
async setAuthorizationFlow(selector: string) {
await this.searchSelect(

View File

@ -1,6 +1,7 @@
import Page from "../page.js";
import { $ } from "@wdio/globals";
import Page from "../page.js";
export class SamlForm extends Page {
async setAuthorizationFlow(selector: string) {
await this.searchSelect(

View File

@ -1,6 +1,7 @@
import Page from "../page.js";
import { $ } from "@wdio/globals";
import Page from "../page.js";
export class TransparentProxyForm extends Page {
async setAuthorizationFlow(selector: string) {
await this.searchSelect(

View File

@ -1,6 +1,7 @@
import { $ } from "@wdio/globals";
import Page from "./page.js";
import UserLibraryPage from "./user-library.page.js";
import { $ } from "@wdio/globals";
/**
* sub page containing specific selectors and methods for a specific page
@ -13,12 +14,16 @@ class LoginPage extends Page {
return await $('input[name="uidField"]');
}
async inputPassword() {
return await $('input[name="password"]');
async usernameBtnSubmit() {
return await $('button[type="submit"]');
}
async btnSubmit() {
return await $('button[type="submit"]');
async inputPassword() {
return await $("input#ak-stage-password-input");
}
async passwordBtnSubmit() {
return await $("ak-stage-password").$('button[type="submit"]');
}
async authFailure() {
@ -31,14 +36,16 @@ class LoginPage extends Page {
async username(username: string) {
await (await this.inputUsername()).setValue(username);
await (await this.btnSubmit()).waitForEnabled();
await (await this.btnSubmit()).click();
const submitBtn = await this.usernameBtnSubmit();
await submitBtn.waitForEnabled();
await submitBtn.click();
}
async password(password: string) {
await (await this.inputPassword()).setValue(password);
await (await this.btnSubmit()).waitForEnabled();
await (await this.btnSubmit()).click();
const submitBtn = await this.passwordBtnSubmit();
await submitBtn.waitForEnabled();
await submitBtn.click();
}
async login(username: string, password: string) {

View File

@ -40,12 +40,17 @@ export default class Page {
await $(`div[data-managed-for="${managedSelector}"]`).$("ak-list-select")
).shadow$$("button");
let target: WebdriverIO.Element;
// @ts-expect-error "Types break on shadow$$"
for (const button of searchBlock) {
if ((await button.getText()).includes(buttonSelector)) {
target = button;
break;
}
}
// @ts-expect-error "TSC cannot tell if the `for` loop actually performs the assignment."
if (!target) {
throw new Error(`Expected to find an entry matching the spec ${buttonSelector}`);
}
await (await target).click();
await browser.keys(Key.Tab);
}

View File

@ -1,6 +1,7 @@
import { $ } from "@wdio/globals";
import AdminPage from "./admin.page.js";
import OauthForm from "./forms/oauth.form.js";
import { $ } from "@wdio/globals";
/**
* sub page containing specific selectors and methods for a specific page

View File

@ -1,7 +1,8 @@
import AdminPage from "./admin.page.js";
import { $, browser } from "@wdio/globals";
import { Key } from "webdriverio";
import AdminPage from "./admin.page.js";
/**
* sub page containing specific selectors and methods for a specific page
*/

View File

@ -1,6 +1,7 @@
import Page from "./page.js";
import { $ } from "@wdio/globals";
import Page from "./page.js";
/**
* sub page containing specific selectors and methods for a specific page
*/

View File

@ -1,6 +1,7 @@
import { expect } from "@wdio/globals";
import LoginPage from "../pageobjects/login.page.js";
import { BAD_PASSWORD, GOOD_USERNAME } from "../utils/constants.js";
import { expect } from "@wdio/globals";
describe("Log into authentik", () => {
it("should fail on a bad password", async () => {

View File

@ -1,6 +1,7 @@
import { expect } from "@wdio/globals";
import LoginPage from "../pageobjects/login.page.js";
import { BAD_USERNAME, GOOD_PASSWORD } from "../utils/constants.js";
import { expect } from "@wdio/globals";
describe("Log into authentik", () => {
it("should fail on a bad username", async () => {

View File

@ -1,8 +1,14 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
// ^^^^^^^^^^^ Because TSC cannot handle metaprogramming, and metaprogramming
// via `defineProperties` is how we installed the OUID finders for the various
// wizard types.
import { expect } from "@wdio/globals";
import ApplicationWizardView from "../pageobjects/application-wizard.page.js";
import ApplicationsListPage from "../pageobjects/applications-list.page.js";
import { randomId } from "../utils/index.js";
import { login } from "../utils/login.js";
import { expect } from "@wdio/globals";
async function reachTheProvider(title: string) {
const newPrefix = randomId();
@ -43,7 +49,6 @@ describe("Configure Applications with the Application Wizard", () => {
await (await ApplicationWizardView.providerList()).waitForDisplayed();
await (await ApplicationWizardView.ldapProvider).scrollIntoView();
await (await ApplicationWizardView.ldapProvider).click();
await (await ApplicationWizardView.nextButton()).click();
await ApplicationWizardView.pause();

View File

@ -1,8 +1,9 @@
import { expect } from "@wdio/globals";
import ProviderWizardView from "../pageobjects/provider-wizard.page.js";
import ProvidersListPage from "../pageobjects/providers-list.page.js";
import { randomId } from "../utils/index.js";
import { login } from "../utils/login.js";
import { expect } from "@wdio/globals";
async function reachTheProvider() {
await ProvidersListPage.logout();
@ -22,11 +23,14 @@ describe("Configure Oauth2 Providers", () => {
await reachTheProvider();
await ProviderWizardView.providerList.waitForDisplayed();
// @ts-expect-error "TSC does not understand metaprogramming."
await ProviderWizardView.oauth2Provider.scrollIntoView();
// @ts-expect-error "TSC does not understand metaprogramming."
await ProviderWizardView.oauth2Provider.click();
await ProviderWizardView.nextButton.click();
await ProviderWizardView.pause();
// @ts-expect-error "TSC does not understand ChainablePromiseElement"
await ProviderWizardView.oauth.providerName.setValue(newProviderName);
await ProviderWizardView.oauth.setAuthorizationFlow(
"default-provider-authorization-explicit-consent",
@ -38,7 +42,7 @@ describe("Configure Oauth2 Providers", () => {
await ProvidersListPage.clickSearchButton();
await ProvidersListPage.pause();
const newProvider = await ProvidersListPage.findProviderRow(newProviderName);
const newProvider = await ProvidersListPage.findProviderRow();
await newProvider.waitForDisplayed();
expect(newProvider).toExist();
expect(await newProvider.getText()).toHaveText(newProviderName);

View File

@ -1,9 +1,17 @@
{
"compilerOptions": {
"strict": true,
"baseUrl": ".",
"moduleResolution": "node",
"module": "ESNext",
"target": "es2022",
"types": ["node", "@wdio/globals/types", "expect-webdriverio", "@wdio/mocha-framework", "@types/mocha"],
"types": [
"node",
"@wdio/globals/types",
"expect-webdriverio",
"@wdio/mocha-framework",
"@types/mocha"
],
"skipLibCheck": true,
"noEmit": true,
"allowImportingTsExtensions": true,
@ -14,5 +22,5 @@
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["test"]
"include": ["."]
}

View File

@ -1,7 +1,8 @@
import { expect } from "@wdio/globals";
import LoginPage from "../pageobjects/login.page.js";
import UserLibraryPage from "../pageobjects/user-library.page.js";
import { GOOD_PASSWORD, GOOD_USERNAME } from "./constants.js";
import { expect } from "@wdio/globals";
export const login = async () => {
await LoginPage.open();

View File

@ -23,7 +23,7 @@ export const config: WebdriverIO.Config = {
// then the current working directory is where your `package.json` resides, so `wdio`
// will be called from there.
//
specs: ["./test/specs/**/*.ts"],
specs: ["./specs/**/*.ts"],
// Patterns to exclude.
exclude: [
// 'path/to/excluded/files'
@ -204,6 +204,7 @@ export const config: WebdriverIO.Config = {
* @param {Array.<String>} specs List of spec file paths that are to be run
* @param {object} browser instance of created browser/device session
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
before: function (_capabilities, _specs) {},
/**
* Runs before a WebdriverIO command gets executed.

View File

@ -57,5 +57,6 @@
}
}
]
}
},
"exclude": ["./tests"]
}

View File

@ -93,7 +93,15 @@ export const config: WebdriverIO.Config = {
"goog:chromeOptions": {
args: [
"disable-search-engine-choice-screen",
...(runHeadless ? ["headless", "disable-gpu", "no-sandbox"] : []),
...(runHeadless
? [
"headless",
"disable-gpu",
"no-sandbox",
"window-size=1280,672",
"browser-test",
]
: []),
],
},
},