mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-12 06:42:59 +00:00
Merge pull request #25 from zitadel/setup-unit-integration-tests
test: setup unit tests
This commit is contained in:
12
.github/pull_request_template.md
vendored
Normal file
12
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
### Definition of Ready
|
||||||
|
|
||||||
|
- [ ] I am happy with the code
|
||||||
|
- [ ] Short description of the feature/issue is added in the pr description
|
||||||
|
- [ ] PR is linked to the corresponding user story
|
||||||
|
- [ ] Acceptance criteria are met
|
||||||
|
- [ ] All open todos and follow ups are defined in a new ticket and justified
|
||||||
|
- [ ] Deviations from the acceptance criteria and design are agreed with the PO and documented.
|
||||||
|
- [ ] Jest unit tests ensure that components produce expected outputs on different inputs.
|
||||||
|
- [ ] Cypress integration tests ensure that login app pages work as expected. The ZITADEL API is mocked.
|
||||||
|
- [ ] No debug or dead code
|
||||||
|
- [ ] My code has no repetitions
|
||||||
26
.github/workflows/test.yml
vendored
Normal file
26
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
name: Test
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup pnpm 7
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 7
|
||||||
|
- name: Setup Node.js 16.x
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 16.x
|
||||||
|
- name: Install Dependencies
|
||||||
|
id: deps
|
||||||
|
run: pnpm install
|
||||||
|
- name: Test
|
||||||
|
id: test
|
||||||
|
run: pnpm test
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -15,5 +15,5 @@ public/dist
|
|||||||
.turbo
|
.turbo
|
||||||
packages/zitadel-server/src/app/proto
|
packages/zitadel-server/src/app/proto
|
||||||
packages/zitadel-client/src/app/proto
|
packages/zitadel-client/src/app/proto
|
||||||
|
.vscode
|
||||||
apps/login/.vscode
|
.idea
|
||||||
|
|||||||
@@ -38,6 +38,25 @@ However, it might be easier to develop against your ZITADEL Cloud instance
|
|||||||
if you don't have docker installed
|
if you don't have docker installed
|
||||||
or have limited resources on your local machine.
|
or have limited resources on your local machine.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
You can execute the following commands in the following directories:
|
||||||
|
|
||||||
|
- apps/login
|
||||||
|
- packages/zitadel-client
|
||||||
|
- packages/zitadel-server
|
||||||
|
- packages/zitadel-react
|
||||||
|
- packages/zitadel-next
|
||||||
|
- The projects root directory: all tests in the project are executed
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Run all once
|
||||||
|
pnpm test
|
||||||
|
|
||||||
|
# Rerun tests on file changes
|
||||||
|
pnpm test:watch
|
||||||
|
```
|
||||||
|
|
||||||
### Developing Against Your Local ZITADEL Instance
|
### Developing Against Your Local ZITADEL Instance
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ Each package and app is 100% [TypeScript](https://www.typescriptlang.org/).
|
|||||||
|
|
||||||
- `pnpm generate` - Build proto stubs for server and client package
|
- `pnpm generate` - Build proto stubs for server and client package
|
||||||
- `pnpm build` - Build all packages and the login app
|
- `pnpm build` - Build all packages and the login app
|
||||||
|
- `pnpm test` - Test all packages and the login app
|
||||||
|
- `pnpm test:watch` - Rerun tests on file change
|
||||||
- `pnpm dev` - Develop all packages and the login app
|
- `pnpm dev` - Develop all packages and the login app
|
||||||
- `pnpm lint` - Lint all packages
|
- `pnpm lint` - Lint all packages
|
||||||
- `pnpm changeset` - Generate a changeset
|
- `pnpm changeset` - Generate a changeset
|
||||||
|
|||||||
0
acceptance/machinekey/.gitkeep
Normal file
0
acceptance/machinekey/.gitkeep
Normal file
@@ -1,4 +1,4 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
extends: "next/core-web-vitals",
|
extends: ["next/core-web-vitals"],
|
||||||
ignorePatterns: ["external/**/*.ts"],
|
ignorePatterns: ["external/**/*.ts"],
|
||||||
};
|
};
|
||||||
|
|||||||
57
apps/login/__test__/PasswordComplexity.test.tsx
Normal file
57
apps/login/__test__/PasswordComplexity.test.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { render, screen, waitFor, within } from "@testing-library/react";
|
||||||
|
import PasswordComplexity from "../ui/PasswordComplexity";
|
||||||
|
// TODO: Why does this not compile?
|
||||||
|
// import { ResourceOwnerType } from '@zitadel/server';
|
||||||
|
|
||||||
|
const matchesTitle = `Matches`;
|
||||||
|
const doesntMatchTitle = `Doesn't match`;
|
||||||
|
|
||||||
|
describe("<PasswordComplexity/>", () => {
|
||||||
|
describe.each`
|
||||||
|
settingsMinLength | password | expectSVGTitle
|
||||||
|
${5} | ${"Password1!"} | ${matchesTitle}
|
||||||
|
${30} | ${"Password1!"} | ${doesntMatchTitle}
|
||||||
|
${0} | ${"Password1!"} | ${matchesTitle}
|
||||||
|
${undefined} | ${"Password1!"} | ${false}
|
||||||
|
`(
|
||||||
|
`With settingsMinLength=$settingsMinLength, password=$password, expectSVGTitle=$expectSVGTitle`,
|
||||||
|
({ settingsMinLength, password, expectSVGTitle }) => {
|
||||||
|
const feedbackElementLabel = /password length/i;
|
||||||
|
beforeEach(() => {
|
||||||
|
render(
|
||||||
|
<PasswordComplexity
|
||||||
|
password={password}
|
||||||
|
equals
|
||||||
|
passwordComplexitySettings={{
|
||||||
|
minLength: settingsMinLength,
|
||||||
|
requiresLowercase: false,
|
||||||
|
requiresUppercase: false,
|
||||||
|
requiresNumber: false,
|
||||||
|
requiresSymbol: false,
|
||||||
|
resourceOwnerType: 0, // ResourceOwnerType.RESOURCE_OWNER_TYPE_UNSPECIFIED,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if (expectSVGTitle === false) {
|
||||||
|
it(`should not render the feedback element`, async () => {
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
screen.queryByText(feedbackElementLabel)
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
it(`Should show one SVG with title ${expectSVGTitle}`, async () => {
|
||||||
|
await waitFor(async () => {
|
||||||
|
const svg = within(
|
||||||
|
screen.getByText(feedbackElementLabel)
|
||||||
|
.parentElement as HTMLElement
|
||||||
|
).findByRole("img");
|
||||||
|
expect(await svg).toHaveTextContent(expectSVGTitle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
7
apps/login/__test__/tsconfig.json
Normal file
7
apps/login/__test__/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsxdev",
|
||||||
|
"types": ["node", "jest", "@testing-library/jest-dom"]
|
||||||
|
}
|
||||||
|
}
|
||||||
19
apps/login/jest.config.ts
Normal file
19
apps/login/jest.config.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import type { Config } from "@jest/types";
|
||||||
|
import { pathsToModuleNameMapper } from "ts-jest";
|
||||||
|
import { compilerOptions } from "./tsconfig.json";
|
||||||
|
|
||||||
|
export default async (): Promise<Config.InitialOptions> => {
|
||||||
|
return {
|
||||||
|
preset: "ts-jest",
|
||||||
|
transform: {
|
||||||
|
"^.+\\.tsx?$": ["ts-jest", { tsconfig: "./__test__/tsconfig.json" }],
|
||||||
|
},
|
||||||
|
setupFilesAfterEnv: ["@testing-library/jest-dom/extend-expect"],
|
||||||
|
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
|
||||||
|
prefix: "<rootDir>/",
|
||||||
|
}),
|
||||||
|
testEnvironment: "jsdom",
|
||||||
|
testRegex: "/__test__/.*\\.test\\.tsx?$",
|
||||||
|
modulePathIgnorePatterns: ["cypress"],
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -2,13 +2,15 @@
|
|||||||
"name": "@zitadel/login",
|
"name": "@zitadel/login",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "next build",
|
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
"test": "jest",
|
||||||
|
"test:watch": "jest --watch",
|
||||||
"lint": "next lint && prettier --check .",
|
"lint": "next lint && prettier --check .",
|
||||||
"lint:fix": "prettier --write .",
|
"lint:fix": "prettier --write .",
|
||||||
"lint-staged": "lint-staged",
|
"lint-staged": "lint-staged",
|
||||||
|
"build": "next build",
|
||||||
|
"prestart": "build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"test": "yarn prettier:check &nexarn lint",
|
|
||||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
|
||||||
},
|
},
|
||||||
"git": {
|
"git": {
|
||||||
@@ -39,24 +41,34 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@bufbuild/buf": "^1.14.0",
|
"@bufbuild/buf": "^1.14.0",
|
||||||
|
"@jest/types": "^29.5.0",
|
||||||
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
|
"@testing-library/react": "^14.0.0",
|
||||||
|
"@types/jest": "^29.5.1",
|
||||||
"@types/ms": "0.7.31",
|
"@types/ms": "0.7.31",
|
||||||
"@types/node": "18.11.9",
|
"@types/node": "18.11.9",
|
||||||
"@types/react": "18.0.25",
|
"@types/react": "18.2.8",
|
||||||
"@types/react-dom": "18.0.9",
|
"@types/react-dom": "18.0.9",
|
||||||
|
"@types/testing-library__jest-dom": "^5.14.6",
|
||||||
"@types/tinycolor2": "1.4.3",
|
"@types/tinycolor2": "1.4.3",
|
||||||
|
"@types/uuid": "^9.0.1",
|
||||||
"@vercel/git-hooks": "1.0.0",
|
"@vercel/git-hooks": "1.0.0",
|
||||||
"@zitadel/tsconfig": "workspace:*",
|
"@zitadel/tsconfig": "workspace:*",
|
||||||
"autoprefixer": "10.4.13",
|
"autoprefixer": "10.4.13",
|
||||||
"del-cli": "5.0.0",
|
"del-cli": "5.0.0",
|
||||||
"eslint-config-zitadel": "workspace:*",
|
"eslint-config-zitadel": "workspace:*",
|
||||||
"grpc-tools": "1.11.3",
|
"grpc-tools": "1.11.3",
|
||||||
|
"jest": "^29.5.0",
|
||||||
|
"jest-environment-jsdom": "^29.5.0",
|
||||||
"lint-staged": "13.0.3",
|
"lint-staged": "13.0.3",
|
||||||
"make-dir-cli": "3.0.0",
|
"make-dir-cli": "3.0.0",
|
||||||
"postcss": "8.4.21",
|
"postcss": "8.4.21",
|
||||||
"prettier-plugin-tailwindcss": "0.1.13",
|
"prettier-plugin-tailwindcss": "0.1.13",
|
||||||
"tailwindcss": "3.2.4",
|
"tailwindcss": "3.2.4",
|
||||||
|
"ts-jest": "^29.1.0",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
"ts-proto": "^1.139.0",
|
"ts-proto": "^1.139.0",
|
||||||
"typescript": "4.8.4",
|
"typescript": "5.0.4",
|
||||||
"zitadel-tailwind-config": "workspace:*"
|
"zitadel-tailwind-config": "workspace:*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
{
|
{
|
||||||
"extends": "@zitadel/tsconfig/nextjs.json",
|
"extends": "@zitadel/tsconfig/nextjs.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"jsx": "preserve",
|
||||||
|
"rootDir": ".",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"#/*": ["./*"]
|
"#/*": ["./*"]
|
||||||
},
|
},
|
||||||
"plugins": [{ "name": "next" }]
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ const check = (
|
|||||||
strokeWidth={1.5}
|
strokeWidth={1.5}
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
className="w-6 h-6 las la-check text-green-500 dark:text-green-500 mr-2 text-lg"
|
className="w-6 h-6 las la-check text-green-500 dark:text-green-500 mr-2 text-lg"
|
||||||
|
role="img"
|
||||||
>
|
>
|
||||||
|
<title>Matches</title>
|
||||||
<path
|
<path
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
@@ -36,7 +38,9 @@ const cross = (
|
|||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
strokeWidth={1.5}
|
strokeWidth={1.5}
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
|
role="img"
|
||||||
>
|
>
|
||||||
|
<title>Doesn't match</title>
|
||||||
<path
|
<path
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
@@ -60,12 +64,16 @@ export default function PasswordComplexity({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-4 grid grid-cols-2 gap-x-8 gap-y-2">
|
<div className="mb-4 grid grid-cols-2 gap-x-8 gap-y-2">
|
||||||
|
{passwordComplexitySettings.minLength != undefined ? (
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
{hasMinLength ? check : cross}
|
{hasMinLength ? check : cross}
|
||||||
<span className={desc}>
|
<span className={desc}>
|
||||||
Password length {passwordComplexitySettings.minLength}
|
Password length {passwordComplexitySettings.minLength}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<span />
|
||||||
|
)}
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
{hasSymbol ? check : cross}
|
{hasSymbol ? check : cross}
|
||||||
<span className={desc}>has Symbol</span>
|
<span className={desc}>has Symbol</span>
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ export default function VerifyEmailForm({ userId, code, submit }: Props) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (submit && code && userId) {
|
if (submit && code && userId) {
|
||||||
submitCode({ code });
|
// When we navigate to this page, we always want to be redirected if submit is true and the parameters are valid.
|
||||||
|
// For programmatic verification, the /verifyemail API should be used.
|
||||||
|
submitCodeAndContinue({ code });
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -53,12 +55,11 @@ export default function VerifyEmailForm({ userId, code, submit }: Props) {
|
|||||||
|
|
||||||
const response = await res.json();
|
const response = await res.json();
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
if (!res.ok) {
|
||||||
setError(response.details);
|
setError(response.details);
|
||||||
return Promise.reject(response);
|
return Promise.reject(response);
|
||||||
} else {
|
} else {
|
||||||
setLoading(false);
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"generate": "turbo run generate",
|
||||||
"build": "turbo run build",
|
"build": "turbo run build",
|
||||||
|
"test": "turbo run test",
|
||||||
|
"test:watch": "turbo run test:watch",
|
||||||
"dev": "turbo run dev --no-cache --continue",
|
"dev": "turbo run dev --no-cache --continue",
|
||||||
"lint": "turbo run lint",
|
"lint": "turbo run lint",
|
||||||
"clean": "turbo run clean && rm -rf node_modules",
|
"clean": "turbo run clean && rm -rf node_modules",
|
||||||
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
|
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
|
||||||
"changeset": "changeset",
|
"changeset": "changeset",
|
||||||
"version-packages": "changeset version",
|
"version-packages": "changeset version",
|
||||||
"release": "turbo run build --filter=login^... && changeset publish",
|
"release": "turbo run build --filter=login^... && changeset publish"
|
||||||
"prebuild": "turbo run generate",
|
|
||||||
"generate": "turbo run generate"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@changesets/cli": "^2.22.0",
|
"@changesets/cli": "^2.22.0",
|
||||||
|
|||||||
8
packages/zitadel-client/jest.config.ts
Normal file
8
packages/zitadel-client/jest.config.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { JestConfigWithTsJest } from 'ts-jest'
|
||||||
|
|
||||||
|
const jestConfig: JestConfigWithTsJest = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node'
|
||||||
|
}
|
||||||
|
|
||||||
|
export default jestConfig
|
||||||
@@ -10,20 +10,27 @@
|
|||||||
"dist/**"
|
"dist/**"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"generate": "buf generate https://github.com/zitadel/zitadel.git --path ./proto/zitadel",
|
||||||
|
"prebuild": "pnpm run generate",
|
||||||
"build": "tsup src/index.ts --format esm,cjs --dts",
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
||||||
|
"test": "jest",
|
||||||
|
"test:watch": "jest --watch",
|
||||||
"dev": "tsup src/index.ts --format esm,cjs --watch --dts",
|
"dev": "tsup src/index.ts --format esm,cjs --watch --dts",
|
||||||
"lint": "eslint \"src/**/*.ts*\"",
|
"lint": "eslint \"src/**/*.ts*\"",
|
||||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
||||||
"generate": "buf generate https://github.com/zitadel/zitadel.git --path ./proto/zitadel"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@bufbuild/buf": "^1.14.0",
|
"@bufbuild/buf": "^1.14.0",
|
||||||
|
"@types/jest": "^29.5.1",
|
||||||
"@zitadel/tsconfig": "workspace:*",
|
"@zitadel/tsconfig": "workspace:*",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-zitadel": "workspace:*",
|
"eslint-config-zitadel": "workspace:*",
|
||||||
|
"jest": "^29.5.0",
|
||||||
|
"ts-jest": "^29.1.0",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
"ts-proto": "^1.139.0",
|
"ts-proto": "^1.139.0",
|
||||||
"tsup": "^5.10.1",
|
"tsup": "^5.10.1",
|
||||||
"typescript": "^4.5.3"
|
"typescript": "^4.9.3"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|||||||
57
packages/zitadel-client/src/middleware.test.ts
Normal file
57
packages/zitadel-client/src/middleware.test.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { CallOptions, ClientMiddlewareCall, Metadata, MethodDescriptor } from "nice-grpc-web";
|
||||||
|
import { authMiddleware } from "./middleware";
|
||||||
|
|
||||||
|
describe('authMiddleware', () => {
|
||||||
|
const scenarios = [
|
||||||
|
{
|
||||||
|
name: 'should add authorization if metadata is undefined',
|
||||||
|
initialMetadata: undefined,
|
||||||
|
expectedMetadata: new Metadata().set("authorization", "Bearer mock-token"),
|
||||||
|
token: "mock-token"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should add authorization if metadata exists but no authorization',
|
||||||
|
initialMetadata: new Metadata().set("other-key", "other-value"),
|
||||||
|
expectedMetadata: new Metadata().set("other-key", "other-value").set("authorization", "Bearer mock-token"),
|
||||||
|
token: "mock-token"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should not modify authorization if it already exists',
|
||||||
|
initialMetadata: new Metadata().set("authorization", "Bearer initial-token"),
|
||||||
|
expectedMetadata: new Metadata().set("authorization", "Bearer initial-token"),
|
||||||
|
token: "mock-token"
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
scenarios.forEach(({ name, initialMetadata, expectedMetadata, token }) => {
|
||||||
|
it(name, async () => {
|
||||||
|
|
||||||
|
const mockNext = jest.fn().mockImplementation(async function*() { });
|
||||||
|
const mockRequest = {};
|
||||||
|
|
||||||
|
const mockMethodDescriptor: MethodDescriptor = {
|
||||||
|
options: {idempotencyLevel: undefined},
|
||||||
|
path: '',
|
||||||
|
requestStream: false,
|
||||||
|
responseStream: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockCall: ClientMiddlewareCall<unknown, unknown> = {
|
||||||
|
method: mockMethodDescriptor,
|
||||||
|
requestStream: false,
|
||||||
|
responseStream: false,
|
||||||
|
request: mockRequest,
|
||||||
|
next: mockNext,
|
||||||
|
};
|
||||||
|
const options: CallOptions = {
|
||||||
|
metadata: initialMetadata
|
||||||
|
};
|
||||||
|
|
||||||
|
await authMiddleware(token)(mockCall, options).next();
|
||||||
|
|
||||||
|
expect(mockNext).toHaveBeenCalledTimes(1);
|
||||||
|
const actualMetadata = mockNext.mock.calls[0][1].metadata;
|
||||||
|
expect(actualMetadata?.get('authorization')).toEqual(expectedMetadata.get('authorization'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
8
packages/zitadel-next/jest.config.ts
Normal file
8
packages/zitadel-next/jest.config.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { JestConfigWithTsJest } from 'ts-jest'
|
||||||
|
|
||||||
|
const jestConfig: JestConfigWithTsJest = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node'
|
||||||
|
}
|
||||||
|
|
||||||
|
export default jestConfig
|
||||||
@@ -11,16 +11,22 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsup src/index.tsx --format esm,cjs --dts --external react",
|
"build": "tsup src/index.tsx --format esm,cjs --dts --external react",
|
||||||
|
"test": "jest",
|
||||||
|
"test:watch": "jest --watch",
|
||||||
"dev": "tsup src/index.tsx --format esm,cjs --watch --dts --external react",
|
"dev": "tsup src/index.tsx --format esm,cjs --watch --dts --external react",
|
||||||
"lint": "eslint \"src/**/*.ts*\"",
|
"lint": "eslint \"src/**/*.ts*\"",
|
||||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/jest": "^29.5.1",
|
||||||
"@zitadel/tsconfig": "workspace:*",
|
"@zitadel/tsconfig": "workspace:*",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-zitadel": "workspace:*",
|
"eslint-config-zitadel": "workspace:*",
|
||||||
|
"jest": "^29.5.0",
|
||||||
|
"ts-jest": "^29.1.0",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
"tsup": "^5.10.1",
|
"tsup": "^5.10.1",
|
||||||
"typescript": "^4.5.3"
|
"typescript": "^4.9.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"next": "^13"
|
"next": "^13"
|
||||||
|
|||||||
5
packages/zitadel-next/src/index.test.tsx
Normal file
5
packages/zitadel-next/src/index.test.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
describe('slug', () => {
|
||||||
|
it('this is not a real test', () => { })
|
||||||
|
})
|
||||||
|
|
||||||
|
export { }
|
||||||
9
packages/zitadel-react/jest.config.ts
Normal file
9
packages/zitadel-react/jest.config.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import type { JestConfigWithTsJest } from 'ts-jest'
|
||||||
|
|
||||||
|
const jestConfig: JestConfigWithTsJest = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'jsdom',
|
||||||
|
setupFilesAfterEnv: [ '@testing-library/jest-dom/extend-expect' ]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default jestConfig
|
||||||
@@ -13,23 +13,33 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsup",
|
"build": "tsup",
|
||||||
|
"test": "jest",
|
||||||
|
"test:watch": "jest --watch",
|
||||||
"dev": "tsup --watch",
|
"dev": "tsup --watch",
|
||||||
"lint": "eslint \"src/**/*.ts*\"",
|
"lint": "eslint \"src/**/*.ts*\"",
|
||||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
|
||||||
"copy-files": "cp -R ./src/public/ ./dist/"
|
"copy-files": "cp -R ./src/public/ ./dist/"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
|
"@testing-library/react": "^14.0.0",
|
||||||
|
"@types/jest": "^29.5.1",
|
||||||
"@types/react": "^17.0.13",
|
"@types/react": "^17.0.13",
|
||||||
"@types/react-dom": "^17.0.8",
|
"@types/react-dom": "^17.0.8",
|
||||||
|
"@types/testing-library__jest-dom": "^5.14.6",
|
||||||
"@zitadel/tsconfig": "workspace:*",
|
"@zitadel/tsconfig": "workspace:*",
|
||||||
"autoprefixer": "10.4.13",
|
"autoprefixer": "10.4.13",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-zitadel": "workspace:*",
|
"eslint-config-zitadel": "workspace:*",
|
||||||
|
"jest": "^29.5.0",
|
||||||
|
"jest-environment-jsdom": "^29.5.0",
|
||||||
"postcss": "8.4.21",
|
"postcss": "8.4.21",
|
||||||
"sass": "^1.62.0",
|
"sass": "^1.62.0",
|
||||||
"tailwindcss": "3.2.4",
|
"tailwindcss": "3.2.4",
|
||||||
|
"ts-jest": "^29.1.0",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
"tsup": "^5.10.1",
|
"tsup": "^5.10.1",
|
||||||
"typescript": "^4.5.3",
|
"typescript": "^4.9.3",
|
||||||
"zitadel-tailwind-config": "workspace:*"
|
"zitadel-tailwind-config": "workspace:*"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { SignInWithGoogle } from './SignInWithGoogle';
|
||||||
|
|
||||||
|
describe('<SignInWithGoogle />', () => {
|
||||||
|
it('renders without crashing', () => {
|
||||||
|
const { container } = render(<SignInWithGoogle />);
|
||||||
|
expect(container.firstChild).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays the correct text', () => {
|
||||||
|
render(<SignInWithGoogle />);
|
||||||
|
const signInText = screen.getByText(/Sign in with Google/i);
|
||||||
|
expect(signInText).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { SignInWithGitlab } from './SignInWithGitlab';
|
||||||
|
|
||||||
|
describe('<SignInWithGitlab />', () => {
|
||||||
|
it('renders without crashing', () => {
|
||||||
|
const { container } = render(<SignInWithGitlab />);
|
||||||
|
expect(container.firstChild).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays the correct text', () => {
|
||||||
|
render(<SignInWithGitlab />);
|
||||||
|
const signInText = screen.getByText(/Sign in with Gitlab/i);
|
||||||
|
expect(signInText).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
8
packages/zitadel-server/jest.config.ts
Normal file
8
packages/zitadel-server/jest.config.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { JestConfigWithTsJest } from 'ts-jest'
|
||||||
|
|
||||||
|
const jestConfig: JestConfigWithTsJest = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node'
|
||||||
|
}
|
||||||
|
|
||||||
|
export default jestConfig
|
||||||
@@ -11,21 +11,27 @@
|
|||||||
"dist/**"
|
"dist/**"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"generate": "buf generate https://github.com/zitadel/zitadel.git --path ./proto/zitadel",
|
||||||
|
"prebuild": "pnpm run generate",
|
||||||
"build": "tsup --dts",
|
"build": "tsup --dts",
|
||||||
|
"test": "jest",
|
||||||
|
"test:watch": "jest --watch",
|
||||||
"dev": "tsup --dts --watch",
|
"dev": "tsup --dts --watch",
|
||||||
"lint": "eslint \"src/**/*.ts*\"",
|
"lint": "eslint \"src/**/*.ts*\"",
|
||||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
||||||
"prebuild": "pnpm run generate",
|
|
||||||
"generate": "buf generate https://github.com/zitadel/zitadel.git --path ./proto/zitadel"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@bufbuild/buf": "^1.14.0",
|
"@bufbuild/buf": "^1.14.0",
|
||||||
|
"@types/jest": "^29.5.1",
|
||||||
"@zitadel/tsconfig": "workspace:*",
|
"@zitadel/tsconfig": "workspace:*",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-zitadel": "workspace:*",
|
"eslint-config-zitadel": "workspace:*",
|
||||||
|
"jest": "^29.5.0",
|
||||||
|
"ts-jest": "^29.1.0",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
"ts-proto": "^1.139.0",
|
"ts-proto": "^1.139.0",
|
||||||
"tsup": "^5.10.1",
|
"tsup": "^5.10.1",
|
||||||
"typescript": "^4.5.3"
|
"typescript": "^4.9.3"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export {
|
|||||||
|
|
||||||
export { type LegalAndSupportSettings } from "./proto/server/zitadel/settings/v2alpha/legal_settings";
|
export { type LegalAndSupportSettings } from "./proto/server/zitadel/settings/v2alpha/legal_settings";
|
||||||
export { type PasswordComplexitySettings } from "./proto/server/zitadel/settings/v2alpha/password_settings";
|
export { type PasswordComplexitySettings } from "./proto/server/zitadel/settings/v2alpha/password_settings";
|
||||||
|
export { type ResourceOwnerType } from "./proto/server/zitadel/settings/v2alpha/settings";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getServers,
|
getServers,
|
||||||
|
|||||||
57
packages/zitadel-server/src/middleware.test.ts
Normal file
57
packages/zitadel-server/src/middleware.test.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { CallOptions, ClientMiddlewareCall, Metadata, MethodDescriptor } from "nice-grpc";
|
||||||
|
import { authMiddleware } from "./middleware";
|
||||||
|
|
||||||
|
describe('authMiddleware', () => {
|
||||||
|
const scenarios = [
|
||||||
|
{
|
||||||
|
name: 'should add authorization if metadata is undefined',
|
||||||
|
initialMetadata: undefined,
|
||||||
|
expectedMetadata: new Metadata().set("authorization", "Bearer mock-token"),
|
||||||
|
token: "mock-token"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should add authorization if metadata exists but no authorization',
|
||||||
|
initialMetadata: new Metadata().set("other-key", "other-value"),
|
||||||
|
expectedMetadata: new Metadata().set("other-key", "other-value").set("authorization", "Bearer mock-token"),
|
||||||
|
token: "mock-token"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should not modify authorization if it already exists',
|
||||||
|
initialMetadata: new Metadata().set("authorization", "Bearer initial-token"),
|
||||||
|
expectedMetadata: new Metadata().set("authorization", "Bearer initial-token"),
|
||||||
|
token: "mock-token"
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
scenarios.forEach(({ name, initialMetadata, expectedMetadata, token }) => {
|
||||||
|
it(name, async () => {
|
||||||
|
|
||||||
|
const mockNext = jest.fn().mockImplementation(async function*() { });
|
||||||
|
const mockRequest = {};
|
||||||
|
|
||||||
|
const mockMethodDescriptor: MethodDescriptor = {
|
||||||
|
options: {idempotencyLevel: undefined},
|
||||||
|
path: '',
|
||||||
|
requestStream: false,
|
||||||
|
responseStream: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockCall: ClientMiddlewareCall<unknown, unknown> = {
|
||||||
|
method: mockMethodDescriptor,
|
||||||
|
requestStream: false,
|
||||||
|
responseStream: false,
|
||||||
|
request: mockRequest,
|
||||||
|
next: mockNext,
|
||||||
|
};
|
||||||
|
const options: CallOptions = {
|
||||||
|
metadata: initialMetadata
|
||||||
|
};
|
||||||
|
|
||||||
|
await authMiddleware(token)(mockCall, options).next();
|
||||||
|
|
||||||
|
expect(mockNext).toHaveBeenCalledTimes(1);
|
||||||
|
const actualMetadata = mockNext.mock.calls[0][1].metadata;
|
||||||
|
expect(actualMetadata?.get('authorization')).toEqual(expectedMetadata.get('authorization'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { CallOptions, ClientMiddlewareCall, Metadata } from "nice-grpc";
|
import { CallOptions, ClientMiddleware, ClientMiddlewareCall, Metadata } from "nice-grpc";
|
||||||
|
|
||||||
export const authMiddleware = (token: string) =>
|
export function authMiddleware (token: string): ClientMiddleware {
|
||||||
async function* <Request, Response>(
|
return async function* <Request, Response>(
|
||||||
call: ClientMiddlewareCall<Request, Response>,
|
call: ClientMiddlewareCall<Request, Response>,
|
||||||
options: CallOptions
|
options: CallOptions
|
||||||
) {
|
) {
|
||||||
@@ -12,6 +12,7 @@ export const authMiddleware = (token: string) =>
|
|||||||
|
|
||||||
return yield* call.next(call.request, options);
|
return yield* call.next(call.request, options);
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const orgMetadata = (orgId: string) =>
|
export const orgMetadata = (orgId: string) =>
|
||||||
new Metadata({ "x-zitadel-orgid": orgId });
|
new Metadata({ "x-zitadel-orgid": orgId });
|
||||||
|
|||||||
4663
pnpm-lock.yaml
generated
4663
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
42
turbo.json
42
turbo.json
@@ -2,16 +2,34 @@
|
|||||||
"$schema": "https://turbo.build/schema.json",
|
"$schema": "https://turbo.build/schema.json",
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"generate": {
|
"generate": {
|
||||||
"outputs": ["src/proto/**"],
|
"outputs": [
|
||||||
|
"src/proto/**"
|
||||||
|
],
|
||||||
"cache": true
|
"cache": true
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"outputs": ["dist/**", ".next/**", "!.next/cache/**"],
|
"outputs": [
|
||||||
"dependsOn": ["generate", "^build"]
|
"dist/**",
|
||||||
|
".next/**",
|
||||||
|
"!.next/cache/**"
|
||||||
|
],
|
||||||
|
"dependsOn": [
|
||||||
|
"lint",
|
||||||
|
"generate",
|
||||||
|
"^build"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
"outputs": ["coverage/**"],
|
"dependsOn": [
|
||||||
"dependsOn": []
|
"generate",
|
||||||
|
"@zitadel/server#build"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"test:watch": {
|
||||||
|
"dependsOn": [
|
||||||
|
"generate",
|
||||||
|
"@zitadel/server#build"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"lint": {},
|
"lint": {},
|
||||||
"dev": {
|
"dev": {
|
||||||
@@ -22,6 +40,16 @@
|
|||||||
"cache": false
|
"cache": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"globalDependencies": ["**/.env.*local"],
|
"globalDependencies": [
|
||||||
"globalEnv": ["ZITADEL_API_URL", "ZITADEL_SERVICE_USER_TOKEN"]
|
"**/.env.*local"
|
||||||
|
],
|
||||||
|
"globalEnv": [
|
||||||
|
"ZITADEL_API_URL",
|
||||||
|
"ZITADEL_SERVICE_USER_TOKEN",
|
||||||
|
"ZITADEL_SYSTEM_API_URL",
|
||||||
|
"ZITADEL_SYSTEM_API_USERID",
|
||||||
|
"ZITADEL_SYSTEM_API_KEY",
|
||||||
|
"ZITADEL_ISSUER",
|
||||||
|
"ZITADEL_ADMIN_TOKEN"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user