mirror of
https://github.com/element-hq/matrix-authentication-service.git
synced 2026-10-23 06:32:59 +00:00
Full page render tests
This commit is contained in:
1 parent
fcd9a6601f
commit
da9bd49be1
34 files changed
+1242
-212
No files matched your search
Generated
+273
-1
@@ -50,6 +50,7 @@
|
||||
"@tanstack/react-query-devtools": "^5.59.20",
|
||||
"@tanstack/router-devtools": "^1.81.5",
|
||||
"@tanstack/router-vite-plugin": "^1.79.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.0.1",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/react": "^18.3.12",
|
||||
@@ -140,6 +141,13 @@
|
||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@adobe/css-tools": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz",
|
||||
"integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||
@@ -3485,6 +3493,15 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@polka/url": {
|
||||
"version": "1.0.0-next.28",
|
||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz",
|
||||
"integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz",
|
||||
@@ -5710,6 +5727,48 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/jest-dom": {
|
||||
"version": "6.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz",
|
||||
"integrity": "sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@adobe/css-tools": "^4.4.0",
|
||||
"aria-query": "^5.0.0",
|
||||
"chalk": "^3.0.0",
|
||||
"css.escape": "^1.5.1",
|
||||
"dom-accessibility-api": "^0.6.3",
|
||||
"lodash": "^4.17.21",
|
||||
"redent": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/jest-dom/node_modules/chalk": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz",
|
||||
"integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@testing-library/react": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz",
|
||||
@@ -5738,6 +5797,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/user-event": {
|
||||
"version": "14.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz",
|
||||
"integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@testing-library/dom": ">=7.21.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/aria-query": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||
@@ -6081,6 +6156,45 @@
|
||||
"vite": "^4.2.0 || ^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/browser": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-2.1.4.tgz",
|
||||
"integrity": "sha512-89SrvShW6kWzmEYtBj5k1gBq88emoC2qrngw5hE1vNpRFteQ5/1URbKIVww391rIALTpzhhCt5yJt5tjLPZxYw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"@vitest/mocker": "2.1.4",
|
||||
"@vitest/utils": "2.1.4",
|
||||
"magic-string": "^0.30.12",
|
||||
"msw": "^2.5.0",
|
||||
"sirv": "^3.0.0",
|
||||
"tinyrainbow": "^1.2.0",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"playwright": "*",
|
||||
"vitest": "2.1.4",
|
||||
"webdriverio": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"playwright": {
|
||||
"optional": true
|
||||
},
|
||||
"safaridriver": {
|
||||
"optional": true
|
||||
},
|
||||
"webdriverio": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/coverage-v8": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.5.tgz",
|
||||
@@ -6118,6 +6232,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.5.tgz",
|
||||
"integrity": "sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "2.1.5",
|
||||
"@vitest/utils": "2.1.5",
|
||||
@@ -6214,6 +6329,30 @@
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/ui": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-2.1.4.tgz",
|
||||
"integrity": "sha512-Zd9e5oU063c+j9N9XzGJagCLNvG71x/2tOme3Js4JEZKX55zsgxhJwUgLI8hkN6NjMLpdJO8d7nVUUuPGAA58Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vitest/utils": "2.1.4",
|
||||
"fflate": "^0.8.2",
|
||||
"flatted": "^3.3.1",
|
||||
"pathe": "^1.1.2",
|
||||
"sirv": "^3.0.0",
|
||||
"tinyglobby": "^0.2.9",
|
||||
"tinyrainbow": "^1.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vitest": "2.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.5.tgz",
|
||||
@@ -6412,7 +6551,6 @@
|
||||
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
}
|
||||
@@ -8357,6 +8495,15 @@
|
||||
"integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fflate": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
||||
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/figures": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
||||
@@ -8403,6 +8550,15 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
|
||||
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
@@ -10564,6 +10720,18 @@
|
||||
"node": ">0.9"
|
||||
}
|
||||
},
|
||||
"node_modules/mrmime": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
|
||||
"integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -12282,6 +12450,33 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/redent": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
|
||||
"integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"indent-string": "^4.0.0",
|
||||
"strip-indent": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/redent/node_modules/strip-indent": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
|
||||
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"min-indent": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||
@@ -12926,6 +13121,23 @@
|
||||
"simple-concat": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sirv": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz",
|
||||
"integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@polka/url": "^1.0.0-next.24",
|
||||
"mrmime": "^2.0.0",
|
||||
"totalist": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
@@ -13809,6 +14021,54 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.10",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz",
|
||||
"integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fdir": "^6.4.2",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/fdir": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz",
|
||||
"integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/tinypool": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz",
|
||||
@@ -13893,6 +14153,18 @@
|
||||
"integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/totalist": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
||||
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tough-cookie": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
"@tanstack/react-query-devtools": "^5.59.20",
|
||||
"@tanstack/router-devtools": "^1.81.5",
|
||||
"@tanstack/router-vite-plugin": "^1.79.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.0.1",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/react": "^18.3.12",
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { cleanup, render } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { render } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { makeFragmentData } from "../../gql/fragment-masking";
|
||||
|
||||
@@ -25,7 +25,6 @@ describe("<OAuth2ClientDetail>", () => {
|
||||
policyUri: "https://client.org/policy",
|
||||
redirectUris: ["https://client.org/"],
|
||||
};
|
||||
afterEach(cleanup);
|
||||
|
||||
it("renders client details", () => {
|
||||
const data = makeFragmentData(baseClient, OAUTH2_CLIENT_FRAGMENT);
|
||||
|
||||
@@ -24,12 +24,13 @@ const QUERY = graphql(/* GraphQL */ `
|
||||
export const query = queryOptions({
|
||||
queryKey: ["footer"],
|
||||
queryFn: ({ signal }) => graphqlRequest({ query: QUERY, signal }),
|
||||
throwOnError: false,
|
||||
});
|
||||
|
||||
const AsyncFooter: React.FC = () => {
|
||||
const result = useQuery(query);
|
||||
|
||||
if (result.error) {
|
||||
if (result.error || result.isPending) {
|
||||
// We probably prefer to render an empty footer in case of an error
|
||||
return null;
|
||||
}
|
||||
@@ -37,7 +38,7 @@ const AsyncFooter: React.FC = () => {
|
||||
const siteConfig = result.data?.siteConfig;
|
||||
if (!siteConfig) {
|
||||
// We checked for errors, this should never happen
|
||||
throw new Error();
|
||||
throw new Error("Failed to load site config");
|
||||
}
|
||||
|
||||
return <Footer siteConfig={siteConfig} />;
|
||||
@@ -49,7 +50,6 @@ const Layout: React.FC<{
|
||||
}> = ({ children, wide }) => (
|
||||
<div className={cx(styles.layoutContainer, wide && styles.wide)}>
|
||||
{children}
|
||||
|
||||
<Suspense fallback={null}>
|
||||
<AsyncFooter />
|
||||
</Suspense>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`<Layout /> > renders app navigation correctly 1`] = `
|
||||
<a
|
||||
aria-current="page"
|
||||
class="_navItem_8603fc"
|
||||
data-status="active"
|
||||
href="/"
|
||||
>
|
||||
Profile
|
||||
</a>
|
||||
`;
|
||||
|
||||
exports[`<Layout /> > renders app navigation correctly 2`] = `
|
||||
<a
|
||||
class="_navItem_8603fc"
|
||||
href="/sessions"
|
||||
>
|
||||
Sessions
|
||||
</a>
|
||||
`;
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { cleanup, render } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { render } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import ClientAvatar from "./ClientAvatar";
|
||||
|
||||
@@ -16,8 +16,6 @@ describe("<ClientAvatar />", () => {
|
||||
const logoUri = "https://www.testclient.com/logo.png";
|
||||
const size = "10px";
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
it("renders client logo", () => {
|
||||
const { container } = render(
|
||||
<ClientAvatar name={name} logoUri={logoUri} size={size} />,
|
||||
|
||||
@@ -7,14 +7,12 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { composeStory } from "@storybook/react";
|
||||
import { cleanup, render } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { render } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import Meta, { Unknown, Pc, Mobile, Tablet } from "./DeviceTypeIcon.stories";
|
||||
|
||||
describe("<DeviceTypeIcon />", () => {
|
||||
afterEach(cleanup);
|
||||
|
||||
it("renders unknown device type", () => {
|
||||
const Component = composeStory(Unknown, Meta);
|
||||
const { container } = render(<Component />);
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { composeStory } from "@storybook/react";
|
||||
import { cleanup, render } from "@testing-library/react";
|
||||
import { afterEach, beforeAll, describe, expect, it } from "vitest";
|
||||
import { render } from "@testing-library/react";
|
||||
import { beforeAll, describe, expect, it } from "vitest";
|
||||
|
||||
import { mockLocale } from "../../test-utils/mockLocale";
|
||||
|
||||
@@ -21,7 +21,6 @@ import Meta, {
|
||||
|
||||
describe("<LastActive", () => {
|
||||
beforeAll(() => mockLocale());
|
||||
afterEach(cleanup);
|
||||
|
||||
it("renders an 'active now' timestamp", () => {
|
||||
const Component = composeStory(ActiveNow, { ...Meta });
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { cleanup } from "@testing-library/react";
|
||||
import { afterEach, beforeAll, describe, expect, it } from "vitest";
|
||||
import { beforeAll, describe, expect, it } from "vitest";
|
||||
import { makeFragmentData } from "../../gql";
|
||||
import { mockLocale } from "../../test-utils/mockLocale";
|
||||
import render from "../../test-utils/render";
|
||||
@@ -29,7 +28,6 @@ describe("<CompatSessionDetail>", () => {
|
||||
};
|
||||
|
||||
beforeAll(() => mockLocale());
|
||||
afterEach(cleanup);
|
||||
|
||||
it("renders a compatability session details", () => {
|
||||
const data = makeFragmentData({ ...baseSession }, FRAGMENT);
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { cleanup } from "@testing-library/react";
|
||||
import { afterEach, beforeAll, describe, expect, it } from "vitest";
|
||||
import { beforeAll, describe, expect, it } from "vitest";
|
||||
|
||||
import { makeFragmentData } from "../../gql";
|
||||
import { mockLocale } from "../../test-utils/mockLocale";
|
||||
@@ -35,7 +34,6 @@ describe("<OAuth2SessionDetail>", () => {
|
||||
};
|
||||
|
||||
beforeAll(() => mockLocale());
|
||||
afterEach(cleanup);
|
||||
|
||||
it("renders session details", () => {
|
||||
const data = makeFragmentData(baseSession, FRAGMENT);
|
||||
|
||||
@@ -7,15 +7,14 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { composeStory } from "@storybook/react";
|
||||
import { cleanup, render } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { render } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { DummyRouter } from "../../test-utils/router";
|
||||
|
||||
import Meta, { Basic } from "./SessionHeader.stories";
|
||||
|
||||
describe("<SessionHeader />", () => {
|
||||
afterEach(cleanup);
|
||||
it("renders a session header", () => {
|
||||
const Component = composeStory(Basic, Meta);
|
||||
const { container } = render(
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { cleanup, fireEvent, render } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { makeFragmentData } from "../../gql/fragment-masking";
|
||||
import { DummyRouter } from "../../test-utils/router";
|
||||
@@ -17,8 +17,6 @@ import UnverifiedEmailAlert, {
|
||||
} from "./UnverifiedEmailAlert";
|
||||
|
||||
describe("<UnverifiedEmailAlert />", () => {
|
||||
afterEach(cleanup);
|
||||
|
||||
it("does not render a warning when there are no unverified emails", () => {
|
||||
const data = makeFragmentData(
|
||||
{
|
||||
|
||||
@@ -15,7 +15,6 @@ import styles from "./UnverifiedEmailAlert.module.css";
|
||||
|
||||
export const UNVERIFIED_EMAILS_FRAGMENT = graphql(/* GraphQL */ `
|
||||
fragment UnverifiedEmailAlert_user on User {
|
||||
id
|
||||
unverifiedEmails: emails(first: 0, state: PENDING) {
|
||||
totalCount
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ export const FRAGMENT = graphql(/* GraphQL */ `
|
||||
|
||||
export const CONFIG_FRAGMENT = graphql(/* GraphQL */ `
|
||||
fragment UserGreeting_siteConfig on SiteConfig {
|
||||
id
|
||||
displayNameChangeAllowed
|
||||
}
|
||||
`);
|
||||
@@ -49,12 +48,6 @@ const SET_DISPLAYNAME_MUTATION = graphql(/* GraphQL */ `
|
||||
mutation SetDisplayName($userId: ID!, $displayName: String) {
|
||||
setDisplayName(input: { userId: $userId, displayName: $displayName }) {
|
||||
status
|
||||
user {
|
||||
id
|
||||
matrix {
|
||||
displayName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { cleanup, render } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { render } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { makeFragmentData } from "../../gql";
|
||||
import { DummyRouter } from "../../test-utils/router";
|
||||
@@ -15,8 +15,6 @@ import { DummyRouter } from "../../test-utils/router";
|
||||
import BrowserSessionsOverview, { FRAGMENT } from "./BrowserSessionsOverview";
|
||||
|
||||
describe("BrowserSessionsOverview", () => {
|
||||
afterEach(cleanup);
|
||||
|
||||
it("renders with no browser sessions", async () => {
|
||||
const user = makeFragmentData(
|
||||
{
|
||||
|
||||
+12
-12
@@ -29,14 +29,14 @@ const documents = {
|
||||
"\n fragment BrowserSession_detail on BrowserSession {\n id\n createdAt\n finishedAt\n userAgent {\n name\n model\n os\n }\n lastActiveIp\n lastActiveAt\n lastAuthentication {\n id\n createdAt\n }\n user {\n id\n username\n }\n }\n": types.BrowserSession_DetailFragmentDoc,
|
||||
"\n fragment CompatSession_detail on CompatSession {\n id\n createdAt\n deviceId\n finishedAt\n lastActiveIp\n lastActiveAt\n userAgent {\n name\n os\n model\n }\n ssoLogin {\n id\n redirectUri\n }\n }\n": types.CompatSession_DetailFragmentDoc,
|
||||
"\n fragment OAuth2Session_detail on Oauth2Session {\n id\n scope\n createdAt\n finishedAt\n lastActiveIp\n lastActiveAt\n client {\n id\n clientId\n clientName\n clientUri\n logoUri\n }\n }\n": types.OAuth2Session_DetailFragmentDoc,
|
||||
"\n fragment UnverifiedEmailAlert_user on User {\n id\n unverifiedEmails: emails(first: 0, state: PENDING) {\n totalCount\n }\n }\n": types.UnverifiedEmailAlert_UserFragmentDoc,
|
||||
"\n fragment UnverifiedEmailAlert_user on User {\n unverifiedEmails: emails(first: 0, state: PENDING) {\n totalCount\n }\n }\n": types.UnverifiedEmailAlert_UserFragmentDoc,
|
||||
"\n fragment UserEmail_email on UserEmail {\n id\n email\n confirmedAt\n }\n": types.UserEmail_EmailFragmentDoc,
|
||||
"\n fragment UserEmail_siteConfig on SiteConfig {\n id\n emailChangeAllowed\n }\n": types.UserEmail_SiteConfigFragmentDoc,
|
||||
"\n mutation RemoveEmail($id: ID!) {\n removeEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n }\n }\n }\n": types.RemoveEmailDocument,
|
||||
"\n mutation SetPrimaryEmail($id: ID!) {\n setPrimaryEmail(input: { userEmailId: $id }) {\n status\n user {\n id\n primaryEmail {\n id\n }\n }\n }\n }\n": types.SetPrimaryEmailDocument,
|
||||
"\n fragment UserGreeting_user on User {\n id\n matrix {\n mxid\n displayName\n }\n }\n": types.UserGreeting_UserFragmentDoc,
|
||||
"\n fragment UserGreeting_siteConfig on SiteConfig {\n id\n displayNameChangeAllowed\n }\n": types.UserGreeting_SiteConfigFragmentDoc,
|
||||
"\n mutation SetDisplayName($userId: ID!, $displayName: String) {\n setDisplayName(input: { userId: $userId, displayName: $displayName }) {\n status\n user {\n id\n matrix {\n displayName\n }\n }\n }\n }\n": types.SetDisplayNameDocument,
|
||||
"\n fragment UserGreeting_siteConfig on SiteConfig {\n displayNameChangeAllowed\n }\n": types.UserGreeting_SiteConfigFragmentDoc,
|
||||
"\n mutation SetDisplayName($userId: ID!, $displayName: String) {\n setDisplayName(input: { userId: $userId, displayName: $displayName }) {\n status\n }\n }\n": types.SetDisplayNameDocument,
|
||||
"\n mutation AddEmail($userId: ID!, $email: String!) {\n addEmail(input: { userId: $userId, email: $email }) {\n status\n violations\n email {\n id\n ...UserEmail_email\n }\n }\n }\n": types.AddEmailDocument,
|
||||
"\n query UserEmailList(\n $userId: ID!\n $first: Int\n $after: String\n $last: Int\n $before: String\n ) {\n user(id: $userId) {\n id\n\n emails(first: $first, after: $after, last: $last, before: $before) {\n edges {\n cursor\n node {\n id\n ...UserEmail_email\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n": types.UserEmailListDocument,
|
||||
"\n fragment UserEmailList_user on User {\n id\n primaryEmail {\n id\n }\n }\n": types.UserEmailList_UserFragmentDoc,
|
||||
@@ -45,12 +45,12 @@ const documents = {
|
||||
"\n fragment UserEmail_verifyEmail on UserEmail {\n id\n email\n }\n": types.UserEmail_VerifyEmailFragmentDoc,
|
||||
"\n mutation DoVerifyEmail($id: ID!, $code: String!) {\n verifyEmail(input: { userEmailId: $id, code: $code }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n": types.DoVerifyEmailDocument,
|
||||
"\n mutation ResendVerificationEmail($id: ID!) {\n sendVerificationEmail(input: { userEmailId: $id }) {\n status\n\n user {\n id\n primaryEmail {\n id\n }\n }\n\n email {\n id\n ...UserEmail_email\n }\n }\n }\n": types.ResendVerificationEmailDocument,
|
||||
"\n query UserProfile {\n viewer {\n __typename\n ... on User {\n id\n\n primaryEmail {\n id\n ...UserEmail_email\n }\n\n ...UserEmailList_user\n }\n }\n\n siteConfig {\n id\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n": types.UserProfileDocument,
|
||||
"\n query UserProfile {\n viewer {\n __typename\n ... on User {\n id\n primaryEmail {\n id\n ...UserEmail_email\n }\n\n ...UserEmailList_user\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n": types.UserProfileDocument,
|
||||
"\n query SessionDetail($id: ID!) {\n viewerSession {\n ... on Node {\n id\n }\n }\n\n node(id: $id) {\n __typename\n id\n ...CompatSession_detail\n ...OAuth2Session_detail\n ...BrowserSession_detail\n }\n }\n": types.SessionDetailDocument,
|
||||
"\n query BrowserSessionList(\n $first: Int\n $after: String\n $last: Int\n $before: String\n $lastActive: DateFilter\n ) {\n viewerSession {\n __typename\n ... on BrowserSession {\n id\n\n user {\n id\n\n browserSessions(\n first: $first\n after: $after\n last: $last\n before: $before\n lastActive: $lastActive\n state: ACTIVE\n ) {\n totalCount\n\n edges {\n cursor\n node {\n id\n ...BrowserSession_session\n }\n }\n\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n }\n }\n": types.BrowserSessionListDocument,
|
||||
"\n query SessionsOverview {\n viewer {\n __typename\n\n ... on User {\n id\n ...BrowserSessionsOverview_user\n }\n }\n }\n": types.SessionsOverviewDocument,
|
||||
"\n query AppSessionsList(\n $before: String\n $after: String\n $first: Int\n $last: Int\n $lastActive: DateFilter\n ) {\n viewer {\n __typename\n\n ... on User {\n id\n appSessions(\n before: $before\n after: $after\n first: $first\n last: $last\n lastActive: $lastActive\n state: ACTIVE\n ) {\n edges {\n cursor\n node {\n __typename\n ...CompatSession_session\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n startCursor\n endCursor\n hasNextPage\n hasPreviousPage\n }\n }\n }\n }\n }\n": types.AppSessionsListDocument,
|
||||
"\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n id\n ...UnverifiedEmailAlert_user\n ...UserGreeting_user\n }\n }\n }\n\n siteConfig {\n id\n ...UserGreeting_siteConfig\n }\n }\n": types.CurrentUserGreetingDocument,
|
||||
"\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n ...UnverifiedEmailAlert_user\n ...UserGreeting_user\n }\n }\n }\n\n siteConfig {\n ...UserGreeting_siteConfig\n }\n }\n": types.CurrentUserGreetingDocument,
|
||||
"\n query OAuth2Client($id: ID!) {\n oauth2Client(id: $id) {\n ...OAuth2Client_detail\n }\n }\n": types.OAuth2ClientDocument,
|
||||
"\n query CurrentViewer {\n viewer {\n __typename\n ... on Node {\n id\n }\n }\n }\n": types.CurrentViewerDocument,
|
||||
"\n query DeviceRedirect($deviceId: String!, $userId: ID!) {\n session(deviceId: $deviceId, userId: $userId) {\n __typename\n ... on Node {\n id\n }\n }\n }\n": types.DeviceRedirectDocument,
|
||||
@@ -58,7 +58,7 @@ const documents = {
|
||||
"\n mutation ChangePassword(\n $userId: ID!\n $oldPassword: String!\n $newPassword: String!\n ) {\n setPassword(\n input: {\n userId: $userId\n currentPassword: $oldPassword\n newPassword: $newPassword\n }\n ) {\n status\n }\n }\n": types.ChangePasswordDocument,
|
||||
"\n query PasswordChange {\n viewer {\n __typename\n ... on Node {\n id\n }\n }\n\n siteConfig {\n ...PasswordCreationDoubleInput_siteConfig\n }\n }\n": types.PasswordChangeDocument,
|
||||
"\n mutation RecoverPassword($ticket: String!, $newPassword: String!) {\n setPasswordByRecovery(\n input: { ticket: $ticket, newPassword: $newPassword }\n ) {\n status\n }\n }\n": types.RecoverPasswordDocument,
|
||||
"\n query PasswordRecovery {\n siteConfig {\n id\n ...PasswordCreationDoubleInput_siteConfig\n }\n }\n": types.PasswordRecoveryDocument,
|
||||
"\n query PasswordRecovery {\n siteConfig {\n ...PasswordCreationDoubleInput_siteConfig\n }\n }\n": types.PasswordRecoveryDocument,
|
||||
"\n mutation AllowCrossSigningReset($userId: ID!) {\n allowUserCrossSigningReset(input: { userId: $userId }) {\n user {\n id\n }\n }\n }\n": types.AllowCrossSigningResetDocument,
|
||||
};
|
||||
|
||||
@@ -121,7 +121,7 @@ export function graphql(source: "\n fragment OAuth2Session_detail on Oauth2Sess
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment UnverifiedEmailAlert_user on User {\n id\n unverifiedEmails: emails(first: 0, state: PENDING) {\n totalCount\n }\n }\n"): typeof import('./graphql').UnverifiedEmailAlert_UserFragmentDoc;
|
||||
export function graphql(source: "\n fragment UnverifiedEmailAlert_user on User {\n unverifiedEmails: emails(first: 0, state: PENDING) {\n totalCount\n }\n }\n"): typeof import('./graphql').UnverifiedEmailAlert_UserFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -145,11 +145,11 @@ export function graphql(source: "\n fragment UserGreeting_user on User {\n i
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment UserGreeting_siteConfig on SiteConfig {\n id\n displayNameChangeAllowed\n }\n"): typeof import('./graphql').UserGreeting_SiteConfigFragmentDoc;
|
||||
export function graphql(source: "\n fragment UserGreeting_siteConfig on SiteConfig {\n displayNameChangeAllowed\n }\n"): typeof import('./graphql').UserGreeting_SiteConfigFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n mutation SetDisplayName($userId: ID!, $displayName: String) {\n setDisplayName(input: { userId: $userId, displayName: $displayName }) {\n status\n user {\n id\n matrix {\n displayName\n }\n }\n }\n }\n"): typeof import('./graphql').SetDisplayNameDocument;
|
||||
export function graphql(source: "\n mutation SetDisplayName($userId: ID!, $displayName: String) {\n setDisplayName(input: { userId: $userId, displayName: $displayName }) {\n status\n }\n }\n"): typeof import('./graphql').SetDisplayNameDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -185,7 +185,7 @@ export function graphql(source: "\n mutation ResendVerificationEmail($id: ID!)
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query UserProfile {\n viewer {\n __typename\n ... on User {\n id\n\n primaryEmail {\n id\n ...UserEmail_email\n }\n\n ...UserEmailList_user\n }\n }\n\n siteConfig {\n id\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n"): typeof import('./graphql').UserProfileDocument;
|
||||
export function graphql(source: "\n query UserProfile {\n viewer {\n __typename\n ... on User {\n id\n primaryEmail {\n id\n ...UserEmail_email\n }\n\n ...UserEmailList_user\n }\n }\n\n siteConfig {\n emailChangeAllowed\n passwordLoginEnabled\n ...UserEmailList_siteConfig\n ...UserEmail_siteConfig\n ...PasswordChange_siteConfig\n }\n }\n"): typeof import('./graphql').UserProfileDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -205,7 +205,7 @@ export function graphql(source: "\n query AppSessionsList(\n $before: String
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n id\n ...UnverifiedEmailAlert_user\n ...UserGreeting_user\n }\n }\n }\n\n siteConfig {\n id\n ...UserGreeting_siteConfig\n }\n }\n"): typeof import('./graphql').CurrentUserGreetingDocument;
|
||||
export function graphql(source: "\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n ...UnverifiedEmailAlert_user\n ...UserGreeting_user\n }\n }\n }\n\n siteConfig {\n ...UserGreeting_siteConfig\n }\n }\n"): typeof import('./graphql').CurrentUserGreetingDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -237,7 +237,7 @@ export function graphql(source: "\n mutation RecoverPassword($ticket: String!,
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query PasswordRecovery {\n siteConfig {\n id\n ...PasswordCreationDoubleInput_siteConfig\n }\n }\n"): typeof import('./graphql').PasswordRecoveryDocument;
|
||||
export function graphql(source: "\n query PasswordRecovery {\n siteConfig {\n ...PasswordCreationDoubleInput_siteConfig\n }\n }\n"): typeof import('./graphql').PasswordRecoveryDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
||||
@@ -1469,7 +1469,7 @@ export type CompatSession_DetailFragment = { __typename?: 'CompatSession', id: s
|
||||
|
||||
export type OAuth2Session_DetailFragment = { __typename?: 'Oauth2Session', id: string, scope: string, createdAt: string, finishedAt?: string | null, lastActiveIp?: string | null, lastActiveAt?: string | null, client: { __typename?: 'Oauth2Client', id: string, clientId: string, clientName?: string | null, clientUri?: string | null, logoUri?: string | null } } & { ' $fragmentName'?: 'OAuth2Session_DetailFragment' };
|
||||
|
||||
export type UnverifiedEmailAlert_UserFragment = { __typename?: 'User', id: string, unverifiedEmails: { __typename?: 'UserEmailConnection', totalCount: number } } & { ' $fragmentName'?: 'UnverifiedEmailAlert_UserFragment' };
|
||||
export type UnverifiedEmailAlert_UserFragment = { __typename?: 'User', unverifiedEmails: { __typename?: 'UserEmailConnection', totalCount: number } } & { ' $fragmentName'?: 'UnverifiedEmailAlert_UserFragment' };
|
||||
|
||||
export type UserEmail_EmailFragment = { __typename?: 'UserEmail', id: string, email: string, confirmedAt?: string | null } & { ' $fragmentName'?: 'UserEmail_EmailFragment' };
|
||||
|
||||
@@ -1491,7 +1491,7 @@ export type SetPrimaryEmailMutation = { __typename?: 'Mutation', setPrimaryEmail
|
||||
|
||||
export type UserGreeting_UserFragment = { __typename?: 'User', id: string, matrix: { __typename?: 'MatrixUser', mxid: string, displayName?: string | null } } & { ' $fragmentName'?: 'UserGreeting_UserFragment' };
|
||||
|
||||
export type UserGreeting_SiteConfigFragment = { __typename?: 'SiteConfig', id: string, displayNameChangeAllowed: boolean } & { ' $fragmentName'?: 'UserGreeting_SiteConfigFragment' };
|
||||
export type UserGreeting_SiteConfigFragment = { __typename?: 'SiteConfig', displayNameChangeAllowed: boolean } & { ' $fragmentName'?: 'UserGreeting_SiteConfigFragment' };
|
||||
|
||||
export type SetDisplayNameMutationVariables = Exact<{
|
||||
userId: Scalars['ID']['input'];
|
||||
@@ -1499,7 +1499,7 @@ export type SetDisplayNameMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type SetDisplayNameMutation = { __typename?: 'Mutation', setDisplayName: { __typename?: 'SetDisplayNamePayload', status: SetDisplayNameStatus, user?: { __typename?: 'User', id: string, matrix: { __typename?: 'MatrixUser', displayName?: string | null } } | null } };
|
||||
export type SetDisplayNameMutation = { __typename?: 'Mutation', setDisplayName: { __typename?: 'SetDisplayNamePayload', status: SetDisplayNameStatus } };
|
||||
|
||||
export type AddEmailMutationVariables = Exact<{
|
||||
userId: Scalars['ID']['input'];
|
||||
@@ -1568,7 +1568,7 @@ export type UserProfileQuery = { __typename?: 'Query', viewer: { __typename: 'An
|
||||
) | null }
|
||||
& { ' $fragmentRefs'?: { 'UserEmailList_UserFragment': UserEmailList_UserFragment } }
|
||||
), siteConfig: (
|
||||
{ __typename?: 'SiteConfig', id: string, emailChangeAllowed: boolean, passwordLoginEnabled: boolean }
|
||||
{ __typename?: 'SiteConfig', emailChangeAllowed: boolean, passwordLoginEnabled: boolean }
|
||||
& { ' $fragmentRefs'?: { 'UserEmailList_SiteConfigFragment': UserEmailList_SiteConfigFragment;'UserEmail_SiteConfigFragment': UserEmail_SiteConfigFragment;'PasswordChange_SiteConfigFragment': PasswordChange_SiteConfigFragment } }
|
||||
) };
|
||||
|
||||
@@ -1631,10 +1631,10 @@ export type CurrentUserGreetingQueryVariables = Exact<{ [key: string]: never; }>
|
||||
|
||||
|
||||
export type CurrentUserGreetingQuery = { __typename?: 'Query', viewerSession: { __typename: 'Anonymous' } | { __typename: 'BrowserSession', id: string, user: (
|
||||
{ __typename?: 'User', id: string }
|
||||
{ __typename?: 'User' }
|
||||
& { ' $fragmentRefs'?: { 'UnverifiedEmailAlert_UserFragment': UnverifiedEmailAlert_UserFragment;'UserGreeting_UserFragment': UserGreeting_UserFragment } }
|
||||
) } | { __typename: 'Oauth2Session' }, siteConfig: (
|
||||
{ __typename?: 'SiteConfig', id: string }
|
||||
{ __typename?: 'SiteConfig' }
|
||||
& { ' $fragmentRefs'?: { 'UserGreeting_SiteConfigFragment': UserGreeting_SiteConfigFragment } }
|
||||
) };
|
||||
|
||||
@@ -1700,7 +1700,7 @@ export type PasswordRecoveryQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type PasswordRecoveryQuery = { __typename?: 'Query', siteConfig: (
|
||||
{ __typename?: 'SiteConfig', id: string }
|
||||
{ __typename?: 'SiteConfig' }
|
||||
& { ' $fragmentRefs'?: { 'PasswordCreationDoubleInput_SiteConfigFragment': PasswordCreationDoubleInput_SiteConfigFragment } }
|
||||
) };
|
||||
|
||||
@@ -1880,7 +1880,6 @@ export const OAuth2Session_DetailFragmentDoc = new TypedDocumentString(`
|
||||
`, {"fragmentName":"OAuth2Session_detail"}) as unknown as TypedDocumentString<OAuth2Session_DetailFragment, unknown>;
|
||||
export const UnverifiedEmailAlert_UserFragmentDoc = new TypedDocumentString(`
|
||||
fragment UnverifiedEmailAlert_user on User {
|
||||
id
|
||||
unverifiedEmails: emails(first: 0, state: PENDING) {
|
||||
totalCount
|
||||
}
|
||||
@@ -1904,7 +1903,6 @@ export const UserGreeting_UserFragmentDoc = new TypedDocumentString(`
|
||||
`, {"fragmentName":"UserGreeting_user"}) as unknown as TypedDocumentString<UserGreeting_UserFragment, unknown>;
|
||||
export const UserGreeting_SiteConfigFragmentDoc = new TypedDocumentString(`
|
||||
fragment UserGreeting_siteConfig on SiteConfig {
|
||||
id
|
||||
displayNameChangeAllowed
|
||||
}
|
||||
`, {"fragmentName":"UserGreeting_siteConfig"}) as unknown as TypedDocumentString<UserGreeting_SiteConfigFragment, unknown>;
|
||||
@@ -2033,12 +2031,6 @@ export const SetDisplayNameDocument = new TypedDocumentString(`
|
||||
mutation SetDisplayName($userId: ID!, $displayName: String) {
|
||||
setDisplayName(input: {userId: $userId, displayName: $displayName}) {
|
||||
status
|
||||
user {
|
||||
id
|
||||
matrix {
|
||||
displayName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`) as unknown as TypedDocumentString<SetDisplayNameMutation, SetDisplayNameMutationVariables>;
|
||||
@@ -2141,7 +2133,6 @@ export const UserProfileDocument = new TypedDocumentString(`
|
||||
}
|
||||
}
|
||||
siteConfig {
|
||||
id
|
||||
emailChangeAllowed
|
||||
passwordLoginEnabled
|
||||
...UserEmailList_siteConfig
|
||||
@@ -2387,19 +2378,16 @@ export const CurrentUserGreetingDocument = new TypedDocumentString(`
|
||||
... on BrowserSession {
|
||||
id
|
||||
user {
|
||||
id
|
||||
...UnverifiedEmailAlert_user
|
||||
...UserGreeting_user
|
||||
}
|
||||
}
|
||||
}
|
||||
siteConfig {
|
||||
id
|
||||
...UserGreeting_siteConfig
|
||||
}
|
||||
}
|
||||
fragment UnverifiedEmailAlert_user on User {
|
||||
id
|
||||
unverifiedEmails: emails(first: 0, state: PENDING) {
|
||||
totalCount
|
||||
}
|
||||
@@ -2412,7 +2400,6 @@ fragment UserGreeting_user on User {
|
||||
}
|
||||
}
|
||||
fragment UserGreeting_siteConfig on SiteConfig {
|
||||
id
|
||||
displayNameChangeAllowed
|
||||
}`) as unknown as TypedDocumentString<CurrentUserGreetingQuery, CurrentUserGreetingQueryVariables>;
|
||||
export const OAuth2ClientDocument = new TypedDocumentString(`
|
||||
@@ -2496,7 +2483,6 @@ export const RecoverPasswordDocument = new TypedDocumentString(`
|
||||
export const PasswordRecoveryDocument = new TypedDocumentString(`
|
||||
query PasswordRecovery {
|
||||
siteConfig {
|
||||
id
|
||||
...PasswordCreationDoubleInput_siteConfig
|
||||
}
|
||||
}
|
||||
|
||||
+40
-17
@@ -4,19 +4,24 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
import type { ExecutionResult } from "graphql";
|
||||
import appConfig from "./config";
|
||||
import type { TypedDocumentString } from "./gql/graphql";
|
||||
|
||||
let base: string;
|
||||
if (import.meta.env.TEST && !window) {
|
||||
base = "http://localhost/";
|
||||
let graphqlEndpoint: string;
|
||||
if (import.meta.env.TEST && typeof window === "undefined") {
|
||||
graphqlEndpoint = new URL(
|
||||
appConfig.graphqlEndpoint,
|
||||
"http:://localhost/",
|
||||
).toString();
|
||||
} else {
|
||||
base = window.location.toString();
|
||||
graphqlEndpoint = new URL(
|
||||
appConfig.graphqlEndpoint,
|
||||
window.location.toString(),
|
||||
).toString();
|
||||
}
|
||||
|
||||
const graphqlEndpoint = new URL(appConfig.graphqlEndpoint, base).toString();
|
||||
|
||||
type RequestOptions<TData, TVariables> = {
|
||||
query: TypedDocumentString<TData, TVariables>;
|
||||
signal?: AbortSignal;
|
||||
@@ -30,17 +35,27 @@ export const graphqlRequest = async <TData, TVariables>({
|
||||
variables,
|
||||
signal,
|
||||
}: RequestOptions<TData, TVariables>): Promise<TData> => {
|
||||
const response = await fetch(graphqlEndpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query,
|
||||
variables,
|
||||
}),
|
||||
signal,
|
||||
});
|
||||
const stack = new Error().stack;
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(graphqlEndpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query,
|
||||
variables,
|
||||
}),
|
||||
signal,
|
||||
});
|
||||
} catch (cause) {
|
||||
const e = new Error(`GraphQL to ${graphqlEndpoint} request failed`, {
|
||||
cause,
|
||||
});
|
||||
e.stack = stack;
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`GraphQL request failed: ${response.status}`);
|
||||
@@ -57,3 +72,11 @@ export const graphqlRequest = async <TData, TVariables>({
|
||||
|
||||
return json.data;
|
||||
};
|
||||
|
||||
export const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
mutations: {
|
||||
throwOnError: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
+16
-14
@@ -81,20 +81,22 @@ const Backend = {
|
||||
},
|
||||
} satisfies BackendModule;
|
||||
|
||||
i18n
|
||||
.use(Backend)
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
fallbackLng: "en",
|
||||
keySeparator: ".",
|
||||
pluralSeparator: ":",
|
||||
defaultNS: "translation",
|
||||
supportedLngs,
|
||||
interpolation: {
|
||||
escapeValue: false, // React has built-in XSS protections
|
||||
},
|
||||
} satisfies InitOptions);
|
||||
export const setupI18n = () => {
|
||||
i18n
|
||||
.use(Backend)
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
fallbackLng: "en",
|
||||
keySeparator: ".",
|
||||
pluralSeparator: ":",
|
||||
defaultNS: "translation",
|
||||
supportedLngs,
|
||||
interpolation: {
|
||||
escapeValue: false, // React has built-in XSS protections
|
||||
},
|
||||
} satisfies InitOptions);
|
||||
};
|
||||
|
||||
import.meta.hot?.on("locales-update", () => {
|
||||
i18n.reloadResources().then(() => {
|
||||
|
||||
+6
-31
@@ -4,45 +4,20 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { RouterProvider, createRouter } from "@tanstack/react-router";
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { RouterProvider } from "@tanstack/react-router";
|
||||
import { TooltipProvider } from "@vector-im/compound-web";
|
||||
import { StrictMode, Suspense } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
|
||||
import ErrorBoundary from "./components/ErrorBoundary";
|
||||
import GenericError from "./components/GenericError";
|
||||
import LoadingScreen from "./components/LoadingScreen";
|
||||
import config from "./config";
|
||||
import i18n from "./i18n";
|
||||
import { routeTree } from "./routeTree.gen";
|
||||
import { queryClient } from "./graphql";
|
||||
import i18n, { setupI18n } from "./i18n";
|
||||
import { router } from "./router";
|
||||
import "./shared.css";
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
mutations: {
|
||||
throwOnError: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Create a new router instance
|
||||
const router = createRouter({
|
||||
routeTree,
|
||||
basepath: config.root,
|
||||
defaultErrorComponent: GenericError,
|
||||
defaultPreload: "intent",
|
||||
defaultPendingMinMs: 0,
|
||||
context: { queryClient },
|
||||
});
|
||||
|
||||
// Register the router instance for type safety
|
||||
declare module "@tanstack/react-router" {
|
||||
interface Register {
|
||||
router: typeof router;
|
||||
}
|
||||
}
|
||||
setupI18n();
|
||||
|
||||
createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
<StrictMode>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { createRouter } from "@tanstack/react-router";
|
||||
import config from "./config";
|
||||
import { queryClient } from "./graphql";
|
||||
import { routeTree } from "./routeTree.gen";
|
||||
|
||||
// Create a new router instance
|
||||
export const router = createRouter({
|
||||
routeTree,
|
||||
basepath: config.root,
|
||||
defaultPreload: "intent",
|
||||
context: { queryClient },
|
||||
});
|
||||
|
||||
// Register the router instance for type safety
|
||||
declare module "@tanstack/react-router" {
|
||||
interface Register {
|
||||
router: typeof router;
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,22 @@
|
||||
import type { QueryClient } from "@tanstack/react-query";
|
||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||
import {
|
||||
type ErrorRouteComponent,
|
||||
Outlet,
|
||||
ScrollRestoration,
|
||||
createRootRouteWithContext,
|
||||
} from "@tanstack/react-router";
|
||||
import { TanStackRouterDevtools } from "@tanstack/router-devtools";
|
||||
import GenericError from "../components/GenericError";
|
||||
import Layout, { query } from "../components/Layout";
|
||||
import NotFound from "../components/NotFound";
|
||||
|
||||
const ErrorComponent: ErrorRouteComponent = ({ error }) => (
|
||||
<Layout>
|
||||
<GenericError error={error} />
|
||||
</Layout>
|
||||
);
|
||||
|
||||
export const Route = createRootRouteWithContext<{
|
||||
queryClient: QueryClient;
|
||||
}>()({
|
||||
@@ -23,7 +31,7 @@ export const Route = createRootRouteWithContext<{
|
||||
<ScrollRestoration />
|
||||
<Outlet />
|
||||
|
||||
{import.meta.env.DEV && (
|
||||
{import.meta.env.DEV && !import.meta.env.TEST && (
|
||||
<>
|
||||
<TanStackRouterDevtools position="bottom-right" />
|
||||
<ReactQueryDevtools buttonPosition="top-right" />
|
||||
@@ -36,6 +44,8 @@ export const Route = createRootRouteWithContext<{
|
||||
context.queryClient.ensureQueryData(query);
|
||||
},
|
||||
|
||||
errorComponent: ErrorComponent,
|
||||
|
||||
notFoundComponent: () => (
|
||||
<Layout>
|
||||
<NotFound />
|
||||
|
||||
@@ -17,7 +17,6 @@ const QUERY = graphql(/* GraphQL */ `
|
||||
__typename
|
||||
... on User {
|
||||
id
|
||||
|
||||
primaryEmail {
|
||||
id
|
||||
...UserEmail_email
|
||||
@@ -28,7 +27,6 @@ const QUERY = graphql(/* GraphQL */ `
|
||||
}
|
||||
|
||||
siteConfig {
|
||||
id
|
||||
emailChangeAllowed
|
||||
passwordLoginEnabled
|
||||
...UserEmailList_siteConfig
|
||||
|
||||
@@ -18,7 +18,6 @@ const QUERY = graphql(/* GraphQL */ `
|
||||
id
|
||||
|
||||
user {
|
||||
id
|
||||
...UnverifiedEmailAlert_user
|
||||
...UserGreeting_user
|
||||
}
|
||||
@@ -26,7 +25,6 @@ const QUERY = graphql(/* GraphQL */ `
|
||||
}
|
||||
|
||||
siteConfig {
|
||||
id
|
||||
...UserGreeting_siteConfig
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import { graphqlRequest } from "../graphql";
|
||||
const QUERY = graphql(/* GraphQL */ `
|
||||
query PasswordRecovery {
|
||||
siteConfig {
|
||||
id
|
||||
...PasswordCreationDoubleInput_siteConfig
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
-1
@@ -5,4 +5,3 @@
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference types="vite-plugin-svgr/client" />
|
||||
@@ -0,0 +1,505 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Account home page > display name edit box > displays an error if the display name is invalid 1`] = `
|
||||
<div
|
||||
aria-describedby="radix-:r45:"
|
||||
aria-labelledby="radix-:r44:"
|
||||
class="_body_9cf7b0"
|
||||
data-state="open"
|
||||
id="radix-:r43:"
|
||||
role="dialog"
|
||||
style="pointer-events: auto;"
|
||||
tabindex="-1"
|
||||
>
|
||||
<h2
|
||||
class="_title_9cf7b0"
|
||||
id="radix-:r44:"
|
||||
>
|
||||
Edit profile
|
||||
</h2>
|
||||
<span
|
||||
aria-label="@user:example.com"
|
||||
class="_avatar_mcap2_17 self-center _avatar-imageless_mcap2_61"
|
||||
data-color="3"
|
||||
data-type="round"
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 88px;"
|
||||
>
|
||||
U
|
||||
</span>
|
||||
bound HTMLFormElement {
|
||||
"0": <input
|
||||
aria-describedby="radix-:r4r:"
|
||||
aria-invalid="true"
|
||||
autocomplete="name"
|
||||
class="_control_9gon8_18 _control_1qov4_22"
|
||||
data-invalid="true"
|
||||
id="radix-:r4k:"
|
||||
name="displayname"
|
||||
title=""
|
||||
type="text"
|
||||
value="User"
|
||||
/>,
|
||||
"1": <button
|
||||
aria-controls=":r4l:"
|
||||
aria-labelledby=":r4m:"
|
||||
class="_action_1qov4_33"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>,
|
||||
"2": <input
|
||||
class="_control_9gon8_18"
|
||||
id="radix-:r4s:"
|
||||
name="mxid"
|
||||
readonly=""
|
||||
title=""
|
||||
value="@user:example.com"
|
||||
/>,
|
||||
"3": <button
|
||||
aria-disabled="false"
|
||||
class="_button_i91xf_17"
|
||||
data-kind="primary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="submit"
|
||||
>
|
||||
Save
|
||||
</button>,
|
||||
}
|
||||
<button
|
||||
class="_button_i91xf_17"
|
||||
data-kind="tertiary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
aria-labelledby=":r4t:"
|
||||
class="_close_9cf7b0"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Account home page > display name edit box > lets edit the display name 1`] = `
|
||||
<div
|
||||
aria-describedby="radix-:rp:"
|
||||
aria-labelledby="radix-:ro:"
|
||||
class="_body_9cf7b0"
|
||||
data-state="open"
|
||||
id="radix-:rn:"
|
||||
role="dialog"
|
||||
style="pointer-events: auto;"
|
||||
tabindex="-1"
|
||||
>
|
||||
<h2
|
||||
class="_title_9cf7b0"
|
||||
id="radix-:ro:"
|
||||
>
|
||||
Edit profile
|
||||
</h2>
|
||||
<span
|
||||
aria-label="@user:example.com"
|
||||
class="_avatar_mcap2_17 self-center _avatar-imageless_mcap2_61"
|
||||
data-color="3"
|
||||
data-type="round"
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 88px;"
|
||||
>
|
||||
U
|
||||
</span>
|
||||
bound HTMLFormElement {
|
||||
"0": <input
|
||||
aria-describedby="radix-:r1f:"
|
||||
autocomplete="name"
|
||||
class="_control_9gon8_18 _control_1qov4_22"
|
||||
id="radix-:r18:"
|
||||
name="displayname"
|
||||
title=""
|
||||
type="text"
|
||||
value="User"
|
||||
/>,
|
||||
"1": <button
|
||||
aria-controls=":r19:"
|
||||
aria-labelledby=":r1a:"
|
||||
class="_action_1qov4_33"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>,
|
||||
"2": <input
|
||||
class="_control_9gon8_18"
|
||||
id="radix-:r1g:"
|
||||
name="mxid"
|
||||
readonly=""
|
||||
title=""
|
||||
value="@user:example.com"
|
||||
/>,
|
||||
"3": <button
|
||||
aria-disabled="false"
|
||||
class="_button_i91xf_17"
|
||||
data-kind="primary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="submit"
|
||||
>
|
||||
Save
|
||||
</button>,
|
||||
}
|
||||
<button
|
||||
class="_button_i91xf_17"
|
||||
data-kind="tertiary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
aria-labelledby=":r1h:"
|
||||
class="_close_9cf7b0"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Account home page > renders the page 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="_layoutContainer_0c8bf9 _wide_0c8bf9"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col gap-4"
|
||||
>
|
||||
<header
|
||||
class="flex justify-between mb-4"
|
||||
>
|
||||
<h1
|
||||
class="_typography_yh5dq_162 _font-heading-lg-semibold_yh5dq_135"
|
||||
>
|
||||
Your account
|
||||
</h1>
|
||||
<button
|
||||
aria-controls="radix-:r0:"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="dialog"
|
||||
class="_button_i91xf_17 _has-icon_i91xf_66 _destructive_i91xf_116"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
data-state="closed"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9 12.031c0-.283.096-.52.288-.712A.968.968 0 0 1 10 11.03h7.15l-1.875-1.875a.96.96 0 0 1-.3-.7c0-.266.108-.508.325-.725a.93.93 0 0 1 .712-.287.977.977 0 0 1 .688.287l3.6 3.6c.1.1.17.209.212.325.042.117.063.242.063.375 0 .134-.02.259-.063.375a.877.877 0 0 1-.212.325l-3.6 3.6a.93.93 0 0 1-.712.288.977.977 0 0 1-.688-.288 1.02 1.02 0 0 1-.313-.712.931.931 0 0 1 .288-.713l1.875-1.875H10a.968.968 0 0 1-.712-.287A.968.968 0 0 1 9 12.03Zm-6-7c0-.55.196-1.02.588-1.412A1.926 1.926 0 0 1 5 3.03h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5v14h6a.97.97 0 0 1 .713.288.968.968 0 0 1 .287.712.97.97 0 0 1-.287.713.968.968 0 0 1-.713.287H5c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 0 1 3 19.03v-14Z"
|
||||
/>
|
||||
</svg>
|
||||
Sign out
|
||||
</button>
|
||||
</header>
|
||||
<div
|
||||
class="_user_66f22a"
|
||||
>
|
||||
<span
|
||||
aria-label="@user:example.com"
|
||||
class="_avatar_mcap2_17 _avatar_66f22a _avatar-imageless_mcap2_61"
|
||||
data-color="3"
|
||||
data-type="round"
|
||||
role="img"
|
||||
style="--cpd-avatar-size: var(--cpd-space-14x);"
|
||||
>
|
||||
U
|
||||
</span>
|
||||
<div
|
||||
class="_meta_66f22a"
|
||||
>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-lg-semibold_yh5dq_83"
|
||||
>
|
||||
User
|
||||
</p>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-md-regular_yh5dq_59 _mxid_66f22a"
|
||||
>
|
||||
@user:example.com
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
aria-controls="radix-:r3:"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="dialog"
|
||||
aria-labelledby=":r6:"
|
||||
class="_icon-button_bh2qc_17 _editButton_66f22a"
|
||||
data-state="closed"
|
||||
role="button"
|
||||
style="--cpd-icon-button-size: var(--cpd-space-6x);"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="_indicator-icon_133tf_26"
|
||||
style="--cpd-icon-button-size: 100%;"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M15.706 2.637a2 2 0 0 1 2.829 0l2.828 2.828a2 2 0 0 1 0 2.829L9.605 20.052a1 1 0 0 1-.465.263L3.483 21.73a1 1 0 0 1-1.212-1.212l1.414-5.657a1 1 0 0 1 .263-.465L15.706 2.637Zm1.224 7.262L14.102 7.07l-8.544 8.544-.943 3.77 3.771-.942L16.93 9.9Z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<nav
|
||||
class="_navBar_214497"
|
||||
>
|
||||
<ul
|
||||
class="_navBarItems_214497"
|
||||
>
|
||||
<li
|
||||
class="_navTab_8603fc"
|
||||
>
|
||||
<a
|
||||
aria-current="page"
|
||||
class="_navItem_8603fc"
|
||||
data-status="active"
|
||||
href="/"
|
||||
>
|
||||
Settings
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
class="_navTab_8603fc"
|
||||
>
|
||||
<a
|
||||
class="_navItem_8603fc"
|
||||
href="/sessions"
|
||||
>
|
||||
Devices
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div
|
||||
class="_blockList_f8cc7f"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col gap-4"
|
||||
id="emails"
|
||||
>
|
||||
bound HTMLFormElement {
|
||||
"0": <input
|
||||
aria-describedby="radix-:rc: radix-:rd:"
|
||||
class="_control_9gon8_18 _userEmailField_e2a518"
|
||||
id="radix-:rb:"
|
||||
name="email"
|
||||
readonly=""
|
||||
title=""
|
||||
type="email"
|
||||
value=""
|
||||
/>,
|
||||
}
|
||||
<div
|
||||
aria-busy="true"
|
||||
class="self-center _mini_0c7436"
|
||||
role="alert"
|
||||
>
|
||||
<svg
|
||||
class="_loadingSpinnerInner_0c7436"
|
||||
fill="none"
|
||||
role="img"
|
||||
viewBox="0 0 100 101"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title>
|
||||
Loading…
|
||||
</title>
|
||||
<path
|
||||
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||
fill="currentFill"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
bound HTMLFormElement {
|
||||
"0": <input
|
||||
aria-describedby="radix-:rf:"
|
||||
class="_control_9gon8_18"
|
||||
id="radix-:re:"
|
||||
name="input"
|
||||
required=""
|
||||
title=""
|
||||
type="email"
|
||||
/>,
|
||||
}
|
||||
</div>
|
||||
<div
|
||||
class="_separator_144s5_17"
|
||||
data-kind="primary"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
bound HTMLFormElement {
|
||||
"0": <input
|
||||
aria-describedby="radix-:rh:"
|
||||
class="_control_9gon8_18"
|
||||
id="radix-:rg:"
|
||||
name="password_preview"
|
||||
readonly=""
|
||||
title=""
|
||||
type="password"
|
||||
value="this looks like a password"
|
||||
/>,
|
||||
}
|
||||
<div
|
||||
class="_separator_144s5_17"
|
||||
data-kind="primary"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
<div
|
||||
data-state="closed"
|
||||
>
|
||||
<button
|
||||
aria-controls="radix-:ri:"
|
||||
aria-expanded="false"
|
||||
class="_trigger_f1daaa"
|
||||
data-state="closed"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="_triggerTitle_f1daaa"
|
||||
>
|
||||
<h1
|
||||
class="_typography_yh5dq_162 _font-heading-sm-semibold_yh5dq_102"
|
||||
>
|
||||
End-to-end encryption
|
||||
</h1>
|
||||
</div>
|
||||
<svg
|
||||
class="_triggerIcon_f1daaa"
|
||||
fill="currentColor"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
width="24px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m12 10.775-3.9 3.9a.948.948 0 0 1-.7.275.948.948 0 0 1-.7-.275.948.948 0 0 1-.275-.7.95.95 0 0 1 .275-.7l4.6-4.6c.1-.1.208-.17.325-.213.117-.041.242-.062.375-.062s.258.02.375.062a.877.877 0 0 1 .325.213l4.6 4.6a.948.948 0 0 1 .275.7.949.949 0 0 1-.275.7.948.948 0 0 1-.7.275.948.948 0 0 1-.7-.275l-3.9-3.9Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div
|
||||
class="_content_f1daaa"
|
||||
data-state="closed"
|
||||
hidden=""
|
||||
id="radix-:ri:"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<footer
|
||||
class="_legalFooter_eb428f"
|
||||
>
|
||||
<nav>
|
||||
<a
|
||||
class="_link_1mzip_17"
|
||||
data-kind="primary"
|
||||
href="https://matrix.org/policy"
|
||||
rel="noreferrer noopener"
|
||||
title="Link to the service privacy policy"
|
||||
>
|
||||
Privacy Policy
|
||||
</a>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="_separator_eb428f"
|
||||
>
|
||||
•
|
||||
</div>
|
||||
<a
|
||||
class="_link_1mzip_17"
|
||||
data-kind="primary"
|
||||
href="https://matrix.org/tos"
|
||||
rel="noreferrer noopener"
|
||||
title="Link to the service terms and conditions"
|
||||
>
|
||||
Terms & Conditions
|
||||
</a>
|
||||
</nav>
|
||||
<p
|
||||
class="_imprint_eb428f"
|
||||
>
|
||||
All Rights Reserved. The Super Chat name, logo and device are registered trade marks of BigCorp Ltd.
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
@@ -0,0 +1,238 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { act, screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { HttpResponse } from "msw";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { UNVERIFIED_EMAILS_FRAGMENT } from "../../../src/components/UnverifiedEmailAlert/UnverifiedEmailAlert";
|
||||
import {
|
||||
CONFIG_FRAGMENT as USER_GREETING_CONFIG_FRAGMENT,
|
||||
FRAGMENT as USER_GREETING_FRAGMENT,
|
||||
} from "../../../src/components/UserGreeting/UserGreeting";
|
||||
import { makeFragmentData } from "../../../src/gql";
|
||||
import {
|
||||
mockCurrentUserGreetingQuery,
|
||||
mockSetDisplayNameMutation,
|
||||
mockUserEmailListQuery,
|
||||
mockUserProfileQuery,
|
||||
} from "../../../src/gql/graphql";
|
||||
import { renderPage, server } from "../render";
|
||||
|
||||
const handlers = [
|
||||
mockCurrentUserGreetingQuery(() =>
|
||||
HttpResponse.json({
|
||||
data: {
|
||||
viewerSession: {
|
||||
__typename: "BrowserSession",
|
||||
|
||||
id: "session-id",
|
||||
user: Object.assign(
|
||||
makeFragmentData(
|
||||
{
|
||||
id: "user-id",
|
||||
matrix: {
|
||||
mxid: "@user:example.com",
|
||||
displayName: "User",
|
||||
},
|
||||
},
|
||||
USER_GREETING_FRAGMENT,
|
||||
),
|
||||
|
||||
makeFragmentData(
|
||||
{
|
||||
unverifiedEmails: {
|
||||
totalCount: 0,
|
||||
},
|
||||
},
|
||||
UNVERIFIED_EMAILS_FRAGMENT,
|
||||
),
|
||||
),
|
||||
},
|
||||
|
||||
siteConfig: makeFragmentData(
|
||||
{
|
||||
displayNameChangeAllowed: true,
|
||||
},
|
||||
USER_GREETING_CONFIG_FRAGMENT,
|
||||
),
|
||||
},
|
||||
}),
|
||||
),
|
||||
|
||||
mockUserProfileQuery(() =>
|
||||
HttpResponse.json({
|
||||
data: {
|
||||
viewer: {
|
||||
__typename: "User",
|
||||
id: "user-id",
|
||||
primaryEmail: {
|
||||
id: "primary-email-id",
|
||||
},
|
||||
},
|
||||
|
||||
siteConfig: {
|
||||
emailChangeAllowed: true,
|
||||
passwordLoginEnabled: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
|
||||
mockUserEmailListQuery(() =>
|
||||
HttpResponse.json({
|
||||
data: {
|
||||
user: {
|
||||
id: "user-id",
|
||||
emails: {
|
||||
edges: [],
|
||||
totalCount: 0,
|
||||
pageInfo: {
|
||||
hasNextPage: false,
|
||||
hasPreviousPage: false,
|
||||
startCursor: null,
|
||||
endCursor: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
];
|
||||
|
||||
describe("Account home page", () => {
|
||||
it("renders the page", async () => {
|
||||
server.use(...handlers);
|
||||
|
||||
const { asFragment } = await renderPage("/");
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("display name edit box", () => {
|
||||
it("lets edit the display name", async () => {
|
||||
// TODO: a better way to wait on delays
|
||||
let advance: () => void;
|
||||
const wait = new Promise((resolve) => {
|
||||
advance = () => resolve(void 0);
|
||||
});
|
||||
|
||||
server.use(
|
||||
mockSetDisplayNameMutation(async ({ variables: { displayName } }) => {
|
||||
await wait;
|
||||
// Double check that the display name posted is the one we expect
|
||||
if (displayName !== "New display name") {
|
||||
throw new Error("Invalid display name");
|
||||
}
|
||||
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
setDisplayName: {
|
||||
__typename: "SetDisplayNamePayload",
|
||||
status: "SET",
|
||||
},
|
||||
},
|
||||
});
|
||||
}),
|
||||
...handlers,
|
||||
);
|
||||
|
||||
const user = userEvent.setup();
|
||||
await renderPage("/");
|
||||
|
||||
// TODO: there is only one 'Edit' button, but we should have better labels
|
||||
const editButton = screen.getByLabelText("Edit");
|
||||
await user.click(editButton);
|
||||
|
||||
const dialog = screen.getByRole("dialog", { name: "Edit profile" });
|
||||
expect(dialog).toBeInTheDocument();
|
||||
expect(dialog).toMatchSnapshot();
|
||||
|
||||
const displayNameInput = screen.getByLabelText("Display name");
|
||||
const newDisplayName = "New display name";
|
||||
await user.clear(displayNameInput);
|
||||
await user.type(displayNameInput, newDisplayName);
|
||||
const saveButton = screen.getByRole("button", { name: "Save" });
|
||||
expect(saveButton).not.toHaveAttribute("aria-disabled", "true");
|
||||
await user.click(saveButton);
|
||||
expect(saveButton).toHaveAttribute("aria-disabled", "true");
|
||||
act(() => advance());
|
||||
waitFor(() => expect(dialog).not.toBeInTheDocument());
|
||||
});
|
||||
|
||||
it("closes with escape", async () => {
|
||||
server.use(...handlers);
|
||||
|
||||
const user = userEvent.setup();
|
||||
await renderPage("/");
|
||||
|
||||
// TODO: there is only one 'Edit' button, but we should have better labels
|
||||
const editButton = screen.getByLabelText("Edit");
|
||||
await user.click(editButton);
|
||||
|
||||
const dialog = screen.getByRole("dialog", { name: "Edit profile" });
|
||||
expect(dialog).toBeInTheDocument();
|
||||
|
||||
await user.keyboard("{esc}");
|
||||
waitFor(() => expect(dialog).not.toBeInTheDocument());
|
||||
});
|
||||
|
||||
it("closes with cancel", async () => {
|
||||
server.use(...handlers);
|
||||
|
||||
const user = userEvent.setup();
|
||||
await renderPage("/");
|
||||
|
||||
// TODO: there is only one 'Edit' button, but we should have better labels
|
||||
const editButton = screen.getByLabelText("Edit");
|
||||
await user.click(editButton);
|
||||
|
||||
const dialog = screen.getByRole("dialog", { name: "Edit profile" });
|
||||
expect(dialog).toBeInTheDocument();
|
||||
|
||||
const cancelButton = screen.getByRole("button", { name: "Cancel" });
|
||||
await user.click(cancelButton);
|
||||
waitFor(() => expect(dialog).not.toBeInTheDocument());
|
||||
});
|
||||
|
||||
it("displays an error if the display name is invalid", async () => {
|
||||
server.use(
|
||||
mockSetDisplayNameMutation(() =>
|
||||
HttpResponse.json({
|
||||
data: {
|
||||
setDisplayName: {
|
||||
__typename: "SetDisplayNamePayload",
|
||||
status: "INVALID",
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
...handlers,
|
||||
);
|
||||
|
||||
const user = userEvent.setup();
|
||||
await renderPage("/");
|
||||
|
||||
// TODO: there is only one 'Edit' button, but we should have better labels
|
||||
const editButton = screen.getByLabelText("Edit");
|
||||
await user.click(editButton);
|
||||
|
||||
const dialog = screen.getByRole("dialog", { name: "Edit profile" });
|
||||
expect(dialog).toBeInTheDocument();
|
||||
|
||||
const displayNameInput = screen.getByRole("textbox", {
|
||||
name: "Display name",
|
||||
});
|
||||
await user.clear(displayNameInput);
|
||||
await user.type(displayNameInput, "Something");
|
||||
const saveButton = screen.getByRole("button", { name: "Save" });
|
||||
await user.click(saveButton);
|
||||
|
||||
expect(displayNameInput).toBeInvalid();
|
||||
expect(dialog).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { RouterProvider, createMemoryHistory } from "@tanstack/react-router";
|
||||
import { type RenderResult, render } from "@testing-library/react";
|
||||
import { TooltipProvider } from "@vector-im/compound-web";
|
||||
import i18n from "i18next";
|
||||
import { HttpResponse } from "msw";
|
||||
import { setupServer } from "msw/node";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import { afterAll, afterEach, beforeAll } from "vitest";
|
||||
import { FRAGMENT } from "../../src/components/Footer/Footer";
|
||||
import { makeFragmentData } from "../../src/gql";
|
||||
import { mockFooterQuery } from "../../src/gql/graphql";
|
||||
import { queryClient } from "../../src/graphql";
|
||||
import { router } from "../../src/router";
|
||||
|
||||
const handlers = [
|
||||
mockFooterQuery(() =>
|
||||
HttpResponse.json({
|
||||
data: {
|
||||
siteConfig: {
|
||||
id: "siteConfig",
|
||||
|
||||
...makeFragmentData(
|
||||
{
|
||||
id: "siteConfig",
|
||||
policyUri: "https://matrix.org/policy",
|
||||
tosUri: "https://matrix.org/tos",
|
||||
imprint:
|
||||
"All Rights Reserved. The Super Chat name, logo and device are registered trade marks of BigCorp Ltd.",
|
||||
},
|
||||
FRAGMENT,
|
||||
),
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
];
|
||||
|
||||
export const server = setupServer(...handlers);
|
||||
|
||||
// Start server before all tests
|
||||
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
|
||||
|
||||
// Close server after all tests
|
||||
afterAll(() => server.close());
|
||||
|
||||
// Reset handlers after each test `important for test isolation`
|
||||
afterEach(() => server.resetHandlers());
|
||||
|
||||
async function renderPage(route: string): Promise<RenderResult> {
|
||||
await router.load();
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: [route],
|
||||
});
|
||||
return render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TooltipProvider>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<RouterProvider
|
||||
router={router}
|
||||
history={history}
|
||||
context={{ queryClient }}
|
||||
/>
|
||||
</I18nextProvider>
|
||||
</TooltipProvider>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
export { renderPage };
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference types="@testing-library/jest-dom" />
|
||||
@@ -17,7 +17,7 @@
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src", "locales", ".storybook/preview.tsx"],
|
||||
"include": ["src", "tests", "locales", ".storybook/preview.tsx"],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
|
||||
@@ -153,7 +153,7 @@ export default defineConfig((env) => ({
|
||||
|
||||
test: {
|
||||
globalSetup: "./vitest.global-setup.ts",
|
||||
setupFiles: ["./vitest.i18n-setup.ts", "./vitest.msw-setup.ts"],
|
||||
setupFiles: "./vitest.setup.ts",
|
||||
coverage: {
|
||||
provider: "v8",
|
||||
src: ["./src/"],
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { HttpResponse } from "msw";
|
||||
import { setupServer } from "msw/node";
|
||||
import { afterAll, afterEach, beforeAll } from "vitest";
|
||||
import { FRAGMENT } from "./src/components/Footer/Footer";
|
||||
import { makeFragmentData } from "./src/gql";
|
||||
import { mockFooterQuery } from "./src/gql/graphql";
|
||||
|
||||
const server = setupServer(
|
||||
mockFooterQuery(() =>
|
||||
HttpResponse.json({
|
||||
data: {
|
||||
siteConfig: {
|
||||
id: "siteConfig",
|
||||
|
||||
...makeFragmentData(
|
||||
{
|
||||
id: "siteConfig",
|
||||
policyUri: "https://matrix.org/policy",
|
||||
tosUri: "https://matrix.org/tos",
|
||||
imprint:
|
||||
"All Rights Reserved. The Super Chat name, logo and device are registered trade marks of BigCorp Ltd.",
|
||||
},
|
||||
FRAGMENT,
|
||||
),
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
// Start server before all tests
|
||||
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
|
||||
|
||||
// Close server after all tests
|
||||
afterAll(() => server.close());
|
||||
|
||||
// Reset handlers after each test `important for test isolation`
|
||||
afterEach(() => server.resetHandlers());
|
||||
@@ -4,9 +4,11 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { cleanup } from "@testing-library/react";
|
||||
import * as i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import { beforeEach } from "vitest";
|
||||
import { afterEach, beforeEach } from "vitest";
|
||||
|
||||
import EN from "./locales/en.json";
|
||||
|
||||
@@ -26,3 +28,5 @@ beforeEach(() => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => cleanup());
|
||||
Reference in new issue
Block a user