@openneuro/app 4.35.0-alpha.1 → 4.36.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/package.json +3 -3
  2. package/src/client.jsx +1 -0
  3. package/src/scripts/components/button/button.scss +14 -0
  4. package/src/scripts/components/search-page/SearchResultItem.tsx +3 -1
  5. package/src/scripts/components/search-page/search-page.scss +1 -13
  6. package/src/scripts/config.ts +6 -0
  7. package/src/scripts/dataset/files/__tests__/__snapshots__/file.spec.jsx.snap +2 -2
  8. package/src/scripts/dataset/files/file.tsx +2 -2
  9. package/src/scripts/dataset/mutations/__tests__/update-file.spec.tsx +126 -0
  10. package/src/scripts/dataset/mutations/update-file.jsx +20 -5
  11. package/src/scripts/dataset/routes/snapshot.tsx +1 -1
  12. package/src/scripts/errors/errorRoute.tsx +2 -0
  13. package/src/scripts/pages/orcid-link.tsx +9 -0
  14. package/src/scripts/queries/user.ts +120 -3
  15. package/src/scripts/types/user-types.ts +11 -13
  16. package/src/scripts/uploader/file-select.tsx +42 -57
  17. package/src/scripts/uploader/upload-select.jsx +1 -1
  18. package/src/scripts/users/__tests__/dataset-card.spec.tsx +127 -0
  19. package/src/scripts/users/__tests__/user-account-view.spec.tsx +150 -67
  20. package/src/scripts/users/__tests__/user-card.spec.tsx +6 -17
  21. package/src/scripts/users/__tests__/user-query.spec.tsx +133 -38
  22. package/src/scripts/users/__tests__/user-routes.spec.tsx +156 -27
  23. package/src/scripts/users/__tests__/user-tabs.spec.tsx +7 -7
  24. package/src/scripts/users/components/edit-list.tsx +26 -5
  25. package/src/scripts/users/components/edit-string.tsx +40 -13
  26. package/src/scripts/users/components/editable-content.tsx +10 -3
  27. package/src/scripts/users/components/user-dataset-filters.tsx +205 -121
  28. package/src/scripts/users/dataset-card.tsx +3 -2
  29. package/src/scripts/users/github-auth-button.tsx +98 -0
  30. package/src/scripts/users/scss/datasetcard.module.scss +65 -12
  31. package/src/scripts/users/scss/useraccountview.module.scss +1 -1
  32. package/src/scripts/users/user-account-view.tsx +43 -34
  33. package/src/scripts/users/user-card.tsx +12 -17
  34. package/src/scripts/users/user-container.tsx +9 -5
  35. package/src/scripts/users/user-datasets-view.tsx +350 -40
  36. package/src/scripts/users/user-menu.tsx +4 -9
  37. package/src/scripts/users/user-notifications-view.tsx +9 -7
  38. package/src/scripts/users/user-query.tsx +3 -3
  39. package/src/scripts/users/user-routes.tsx +11 -5
  40. package/src/scripts/users/user-tabs.tsx +4 -2
  41. package/src/scripts/users/__tests__/datasest-card.spec.tsx +0 -201
  42. package/src/scripts/users/fragments/query.js +0 -42
@@ -0,0 +1,127 @@
1
+ import React from "react"
2
+ import { render, screen } from "@testing-library/react"
3
+ import DatasetCard from "../dataset-card"
4
+
5
+ const mockDataset = {
6
+ id: "ds000001",
7
+ name: "Test Dataset",
8
+ created: "2025-01-01T00:00:00Z",
9
+ public: true,
10
+ analytics: {
11
+ downloads: 12345,
12
+ views: 67890,
13
+ },
14
+ followers: [
15
+ { userId: "user1", datasetId: "ds000001" },
16
+ { userId: "user2", datasetId: "ds000001" },
17
+ ],
18
+ stars: [
19
+ { userId: "user1", datasetId: "ds000001" },
20
+ ],
21
+ latestSnapshot: {
22
+ id: "ds000001:1.0.0",
23
+ size: 1024 ** 3,
24
+ issues: [{ severity: "low" }],
25
+ created: "2025-01-01T00:00:00Z",
26
+ description: {
27
+ Name: "Test Dataset Description",
28
+ Authors: ["John Doe"],
29
+ SeniorAuthor: "Dr. Smith",
30
+ DatasetType: "fMRI",
31
+ },
32
+ summary: {
33
+ modalities: ["fMRI"],
34
+ secondaryModalities: [],
35
+ sessions: 1,
36
+ subjects: 1,
37
+ subjectMetadata: [],
38
+ tasks: ["rest"],
39
+ size: 1024 ** 3,
40
+ totalFiles: 10,
41
+ dataProcessed: true,
42
+ pet: null,
43
+ },
44
+ validation: {
45
+ errors: [],
46
+ warnings: [],
47
+ },
48
+ },
49
+ uploader: {
50
+ id: "uploaderId123",
51
+ name: "Uploader Name",
52
+ orcid: "1234-5678-9012-3456",
53
+ },
54
+ permissions: {
55
+ id: "somePermId",
56
+ userPermissions: [
57
+ {
58
+ userId: "someUserId",
59
+ level: "admin",
60
+ access: "admin",
61
+ user: {
62
+ id: "someUser",
63
+ name: "Some User",
64
+ email: "some@user.com",
65
+ provider: "github",
66
+ },
67
+ },
68
+ ],
69
+ },
70
+ metadata: { ages: [20] },
71
+ snapshots: [
72
+ {
73
+ id: "ds000001:1.0.0",
74
+ created: "2025-01-01T00:00:00Z",
75
+ tag: "1.0.0",
76
+ },
77
+ ],
78
+ }
79
+
80
+ describe("DatasetCard", () => {
81
+ it("should render dataset information correctly", () => {
82
+ render(<DatasetCard dataset={mockDataset} hasEdit={false} />)
83
+ expect(screen.getByText("Test Dataset")).toBeInTheDocument()
84
+ expect(screen.getByText("ds000001")).toBeInTheDocument()
85
+ })
86
+
87
+ it("should hide the dataset if not public and hasEdit is false", () => {
88
+ const privateDataset = { ...mockDataset, public: false }
89
+ const { container } = render(
90
+ <DatasetCard dataset={privateDataset} hasEdit={false} />,
91
+ )
92
+ expect(container).toBeEmptyDOMElement()
93
+ })
94
+
95
+ it("should show the dataset if not public but hasEdit is true", () => {
96
+ const privateDataset = { ...mockDataset, public: false }
97
+ render(<DatasetCard dataset={privateDataset} hasEdit={true} />)
98
+ expect(screen.getByText("Test Dataset")).toBeInTheDocument()
99
+ })
100
+
101
+ it("should render activity details correctly", () => {
102
+ render(<DatasetCard dataset={mockDataset} hasEdit={false} />)
103
+ expect(screen.getByRole("img", { name: /activity/i })).toBeInTheDocument()
104
+ })
105
+
106
+ it("should render public icon if dataset is public", () => {
107
+ render(<DatasetCard dataset={mockDataset} hasEdit={false} />)
108
+ expect(screen.getByLabelText("Public")).toBeInTheDocument()
109
+ })
110
+
111
+ it("should not render public icon if dataset is not public", () => {
112
+ const privateDataset = { ...mockDataset, public: false }
113
+ render(<DatasetCard dataset={privateDataset} hasEdit={true} />)
114
+ expect(screen.queryByLabelText("Public")).not.toBeInTheDocument()
115
+ })
116
+
117
+ it("should display 'Unknown size' if latestSnapshot or size is missing", () => {
118
+ const datasetWithoutSize = {
119
+ ...mockDataset,
120
+ latestSnapshot: { ...mockDataset.latestSnapshot, size: undefined },
121
+ }
122
+ render(<DatasetCard dataset={datasetWithoutSize} hasEdit={false} />)
123
+ expect(screen.getByText("Dataset Size:")).toHaveTextContent(
124
+ "Dataset Size: Unknown size",
125
+ )
126
+ })
127
+ })
@@ -1,4 +1,3 @@
1
- import { vi } from "vitest"
2
1
  import React from "react"
3
2
  import { MockedProvider } from "@apollo/client/testing"
4
3
  import {
@@ -11,6 +10,7 @@ import {
11
10
  import { UserAccountView } from "../user-account-view"
12
11
  import type { User } from "../../types/user-types"
13
12
  import * as userQueries from "../../queries/user"
13
+ import { BrowserRouter } from "react-router-dom"
14
14
 
15
15
  const baseUser: User = {
16
16
  id: "1",
@@ -22,76 +22,93 @@ const baseUser: User = {
22
22
  avatar: "https://dummyimage.com/200x200/000/fff",
23
23
  orcid: "0000-0000-0000-0000",
24
24
  links: [],
25
+ admin: false,
26
+ provider: "orcid",
27
+ created: new Date("2025-05-20T14:50:32.424Z"),
28
+ lastSeen: new Date("2025-05-20T14:50:32.424Z"),
29
+ blocked: false,
30
+ githubSynced: null,
25
31
  }
26
32
 
27
- vi.mock("../../queries/user", async () => {
28
- const actual = await vi.importActual("../../queries/user")
29
- return {
30
- ...actual,
31
- useUser: () => ({
32
- user: baseUser,
33
- loading: false,
34
- error: undefined,
35
- }),
36
- }
37
- })
38
-
39
- const mocks = [
40
- {
41
- request: {
42
- query: userQueries.GET_USER,
43
- variables: { id: baseUser.orcid },
44
- },
45
- result: {
46
- data: {
47
- user: baseUser,
48
- },
49
- },
33
+ const userMock = {
34
+ request: {
35
+ query: userQueries.GET_USER,
36
+ variables: { id: baseUser.orcid },
50
37
  },
51
- {
52
- request: {
53
- query: userQueries.UPDATE_USER,
54
- variables: {
55
- id: baseUser.orcid,
56
- location: "Marin, CA",
57
- links: ["https://newlink.com"],
58
- institution: "New University",
59
- },
60
- },
61
- result: {
62
- data: {
63
- updateUser: {
64
- id: baseUser.orcid,
65
- location: "Marin, CA",
66
- links: ["https://newlink.com"],
67
- institution: "New University",
68
- },
69
- },
38
+ result: {
39
+ data: {
40
+ user: baseUser,
70
41
  },
71
42
  },
72
- ]
43
+ }
73
44
 
74
45
  describe("<UserAccountView />", () => {
75
- it("should render the user details correctly", () => {
46
+ it("should render the user details correctly", async () => {
47
+ const mocks = [
48
+ userMock,
49
+ {
50
+ request: {
51
+ query: userQueries.UPDATE_USER,
52
+ variables: {
53
+ id: baseUser.orcid,
54
+ },
55
+ },
56
+ result: {
57
+ data: {
58
+ updateUser: {
59
+ id: baseUser.orcid,
60
+ location: "Marin, CA",
61
+ links: ["https://newlink.com"],
62
+ institution: "New University",
63
+ },
64
+ },
65
+ },
66
+ },
67
+ ]
76
68
  render(
77
- <MockedProvider mocks={mocks} addTypename={false}>
78
- <UserAccountView />
79
- </MockedProvider>,
69
+ <BrowserRouter>
70
+ <MockedProvider mocks={mocks} addTypename={false}>
71
+ <UserAccountView orcidUser={baseUser} />
72
+ </MockedProvider>
73
+ </BrowserRouter>,
80
74
  )
81
- expect(screen.getByText("Name:")).toBeInTheDocument()
82
75
  expect(screen.getByText("John Doe")).toBeInTheDocument()
76
+ expect(screen.getByText("Name:")).toBeInTheDocument()
83
77
  expect(screen.getByText("Email:")).toBeInTheDocument()
84
78
  expect(screen.getByText("john.doe@example.com")).toBeInTheDocument()
85
79
  expect(screen.getByText("ORCID:")).toBeInTheDocument()
86
80
  expect(screen.getByText("0000-0000-0000-0000")).toBeInTheDocument()
87
- expect(screen.getByText("Connect your GitHub")).toBeInTheDocument()
81
+ expect(screen.getByText("Link user data from GitHub")).toBeInTheDocument()
88
82
  })
89
-
90
- it("should render location with EditableContent", async () => {
83
+ it("should render location with EditableContent and update", async () => {
84
+ const mocks = [
85
+ userMock,
86
+ {
87
+ request: {
88
+ query: userQueries.UPDATE_USER,
89
+ variables: {
90
+ id: baseUser.orcid,
91
+ location: "Marin, CA",
92
+ },
93
+ },
94
+ result: {
95
+ data: {
96
+ updateUser: {
97
+ id: baseUser.orcid,
98
+ location: "Marin, CA",
99
+ links: ["https://newlink.com"],
100
+ institution: "New University",
101
+ },
102
+ },
103
+ },
104
+ },
105
+ ]
91
106
  render(
92
- <MockedProvider mocks={mocks} addTypename={false}>
93
- <UserAccountView />
94
- </MockedProvider>,
107
+ <BrowserRouter>
108
+ <MockedProvider mocks={mocks} addTypename={false}>
109
+ <UserAccountView orcidUser={baseUser} />
110
+ </MockedProvider>
111
+ </BrowserRouter>,
95
112
  )
96
113
  const locationSection = within(screen.getByTestId("location-section"))
97
114
  expect(screen.getByText("Location")).toBeInTheDocument()
@@ -106,11 +123,32 @@ describe("<UserAccountView />", () => {
106
123
  })
107
124
  })
108
125
 
109
- it("should render institution with EditableContent", async () => {
126
+ it("should render institution with EditableContent and update", async () => {
127
+ const mocks = [userMock, {
128
+ request: {
129
+ query: userQueries.UPDATE_USER,
130
+ variables: {
131
+ id: baseUser.orcid,
132
+ institution: "New University",
133
+ },
134
+ },
135
+ result: {
136
+ data: {
137
+ updateUser: {
138
+ id: baseUser.orcid,
139
+ location: "Marin, CA",
140
+ links: ["https://newlink.com"],
141
+ institution: "New University",
142
+ },
143
+ },
144
+ },
145
+ }]
110
146
  render(
111
- <MockedProvider mocks={mocks} addTypename={false}>
112
- <UserAccountView />
113
- </MockedProvider>,
147
+ <BrowserRouter>
148
+ <MockedProvider mocks={mocks} addTypename={false}>
149
+ <UserAccountView orcidUser={baseUser} />
150
+ </MockedProvider>,
151
+ </BrowserRouter>,
114
152
  )
115
153
  const institutionSection = within(screen.getByTestId("institution-section"))
116
154
  expect(screen.getByText("Institution")).toBeInTheDocument()
@@ -125,11 +163,32 @@ describe("<UserAccountView />", () => {
125
163
  })
126
164
  })
127
165
 
128
- it("should render links with EditableContent and validation", async () => {
166
+ it("should render links with EditableContent and handle valid URL input", async () => {
167
+ const mocks = [userMock, {
168
+ request: {
169
+ query: userQueries.UPDATE_USER,
170
+ variables: {
171
+ id: baseUser.orcid,
172
+ links: ["https://newlink.com"],
173
+ },
174
+ },
175
+ result: {
176
+ data: {
177
+ updateUser: {
178
+ id: baseUser.orcid,
179
+ location: "Marin, CA",
180
+ links: ["https://newlink.com"],
181
+ institution: "New University",
182
+ },
183
+ },
184
+ },
185
+ }]
129
186
  render(
130
- <MockedProvider mocks={mocks} addTypename={false}>
131
- <UserAccountView />
132
- </MockedProvider>,
187
+ <BrowserRouter>
188
+ <MockedProvider mocks={mocks} addTypename={false}>
189
+ <UserAccountView orcidUser={baseUser} />
190
+ </MockedProvider>,
191
+ </BrowserRouter>,
133
192
  )
134
193
  const linksSection = within(screen.getByTestId("links-section"))
135
194
  expect(screen.getByText("Links")).toBeInTheDocument()
@@ -145,11 +204,33 @@ describe("<UserAccountView />", () => {
145
204
  })
146
205
 
147
206
  it("should show an error message when invalid URL is entered in links section", async () => {
207
+ const mocks = [{
208
+ request: {
209
+ query: userQueries.UPDATE_USER,
210
+ variables: {
211
+ id: baseUser.orcid,
212
+ links: ["https://newlink.com"],
213
+ },
214
+ },
215
+ result: {
216
+ data: {
217
+ updateUser: {
218
+ id: baseUser.orcid,
219
+ location: "Marin, CA",
220
+ links: ["https://newlink.com"],
221
+ institution: "New University",
222
+ },
223
+ },
224
+ },
225
+ }]
148
226
  render(
149
- <MockedProvider mocks={mocks} addTypename={false}>
150
- <UserAccountView />
151
- </MockedProvider>,
227
+ <BrowserRouter>
228
+ <MockedProvider mocks={mocks} addTypename={false}>
229
+ <UserAccountView orcidUser={baseUser} />
230
+ </MockedProvider>,
231
+ </BrowserRouter>,
152
232
  )
233
+
153
234
  const linksSection = within(screen.getByTestId("links-section"))
154
235
  const editButton = linksSection.getByText("Edit")
155
236
  fireEvent.click(editButton)
@@ -159,7 +240,9 @@ describe("<UserAccountView />", () => {
159
240
  fireEvent.click(saveButton)
160
241
  await waitFor(() => {
161
242
  expect(
162
- linksSection.getByText("Invalid URL format. Please use a valid link."),
243
+ linksSection.getByText(
244
+ "Invalid URL format. Please start with http:// or https://",
245
+ ),
163
246
  ).toBeInTheDocument()
164
247
  })
165
248
  })
@@ -1,18 +1,7 @@
1
1
  import React from "react"
2
2
  import { render, screen } from "@testing-library/react"
3
3
  import { UserCard } from "../user-card"
4
-
5
- interface User {
6
- id: string
7
- name: string
8
- location: string
9
- github?: string
10
- institution: string
11
- email: string
12
- avatar: string
13
- orcid: string
14
- links: string[]
15
- }
4
+ import type { User } from "../../types/user-types"
16
5
 
17
6
  describe("UserCard Component", () => {
18
7
  const baseUser: User = {
@@ -28,7 +17,7 @@ describe("UserCard Component", () => {
28
17
  }
29
18
 
30
19
  it("renders all user details when all data is provided", () => {
31
- render(<UserCard user={baseUser} />)
20
+ render(<UserCard orcidUser={baseUser} />)
32
21
 
33
22
  const orcidLink = screen.getByRole("link", {
34
23
  name: "ORCID profile of John Doe",
@@ -67,7 +56,7 @@ describe("UserCard Component", () => {
67
56
  institution: "",
68
57
  }
69
58
 
70
- render(<UserCard user={minimalUser} />)
59
+ render(<UserCard orcidUser={minimalUser} />)
71
60
 
72
61
  const orcidLink = screen.getByRole("link", {
73
62
  name: "ORCID profile of Jane Doe",
@@ -91,13 +80,13 @@ describe("UserCard Component", () => {
91
80
  name: "John Smith",
92
81
  email: "johnsmith@example.com",
93
82
  orcid: "0000-0003-4567-8901",
94
- links: [], // Empty links
83
+ links: [],
95
84
  avatar: "https://example.com/avatar.jpg",
96
85
  location: "New York, NY",
97
86
  institution: "NYU",
98
87
  }
99
88
 
100
- render(<UserCard user={userWithEmptyLinks} />)
89
+ render(<UserCard orcidUser={userWithEmptyLinks} />)
101
90
 
102
91
  expect(screen.queryByRole("link", { name: "https://example.com" })).not
103
92
  .toBeInTheDocument()
@@ -117,7 +106,7 @@ describe("UserCard Component", () => {
117
106
  institution: "",
118
107
  }
119
108
 
120
- render(<UserCard user={userWithoutLocationAndInstitution} />)
109
+ render(<UserCard orcidUser={userWithoutLocationAndInstitution} />)
121
110
 
122
111
  const orcidLink = screen.getByRole("link", {
123
112
  name: "ORCID profile of Emily Doe",
@@ -1,44 +1,137 @@
1
+ import { vi } from "vitest"
1
2
  import React from "react"
2
- import { render, screen, waitFor } from "@testing-library/react"
3
+ import { render, screen } from "@testing-library/react"
3
4
  import { MockedProvider } from "@apollo/client/testing"
4
5
  import { MemoryRouter, Route, Routes } from "react-router-dom"
6
+
7
+ // Component
5
8
  import { UserQuery } from "../user-query"
6
- import { GET_USER } from "../../queries/user"
7
- import * as ProfileUtils from "../../authentication/profile"
9
+ import { isValidOrcid } from "../../utils/validationUtils"
10
+ import { getProfile } from "../../authentication/profile"
11
+ import { isAdmin } from "../../authentication/admin-user"
12
+ import { useCookies } from "react-cookie"
13
+ import { useUser } from "../../queries/user"
14
+ import type { User } from "../../types/user-types"
15
+ import type { UserRoutesProps } from "../../types/user-types"
8
16
 
9
- Object.defineProperty(ProfileUtils, "getProfile", {
10
- value: () => ({ sub: "1" }),
11
- writable: true,
12
- })
17
+ // --- generate a random valid ORCID - maybe unnecessary ---
18
+ const generateRandomValidOrcid = (): string => {
19
+ const segments = Array.from(
20
+ { length: 4 },
21
+ () => Math.floor(1000 + Math.random() * 9000).toString(),
22
+ )
23
+ return segments.join("-")
24
+ }
13
25
 
14
- const validOrcid = "0009-0001-9689-7232"
26
+ vi.mock("./user-routes", () => ({
27
+ UserRoutes: vi.fn((props: UserRoutesProps) => (
28
+ <div data-testid="mock-user-routes">
29
+ Mocked UserRoutes Component
30
+ <p>User ORCID: {props.orcidUser?.orcid}</p>
31
+ <p>Has Edit: {props.hasEdit ? "true" : "false"}</p>
32
+ <p>Is User: {props.isUser ? "true" : "false"}</p>
33
+ </div>
34
+ )),
35
+ }))
15
36
 
16
- const userMock = {
17
- request: {
18
- query: GET_USER,
19
- variables: { userId: "1" },
20
- },
21
- result: {
22
- data: {
23
- user: {
24
- __typename: "User",
25
- id: "1",
26
- name: "Test User",
27
- orcid: validOrcid,
28
- email: "test@example.com",
29
- avatar: "http://example.com/avatar.png",
37
+ vi.mock("../../utils/validationUtils", () => ({
38
+ isValidOrcid: vi.fn<typeof isValidOrcid>(),
39
+ }))
40
+
41
+ vi.mock("react-cookie", () => ({
42
+ useCookies: vi.fn<typeof useCookies>(),
43
+ }))
44
+
45
+ vi.mock("../../authentication/profile", () => ({
46
+ getProfile: vi.fn<typeof getProfile>(),
47
+ }))
48
+
49
+ vi.mock("../../authentication/admin-user", () => ({
50
+ isAdmin: vi.fn<typeof isAdmin>(),
51
+ }))
52
+
53
+ vi.mock("../../queries/user", () => ({
54
+ useUser: vi.fn<typeof useUser>(),
55
+ ADVANCED_SEARCH_DATASETS_QUERY: {
56
+ kind: "Document",
57
+ definitions: [
58
+ {
59
+ kind: "OperationDefinition",
60
+ operation: "query",
61
+ name: { kind: "Name", value: "AdvancedSearchDatasets" },
62
+ variableDefinitions: [],
63
+ selectionSet: { kind: "SelectionSet", selections: [] },
64
+ },
65
+ ],
66
+ loc: {
67
+ start: 0,
68
+ end: 0,
69
+ source: {
70
+ body: "",
71
+ name: "Mocked",
72
+ locationOffset: { line: 1, column: 1 },
30
73
  },
31
74
  },
32
75
  },
76
+ }))
77
+
78
+ export interface OpenNeuroTokenProfile {
79
+ sub: string
80
+ admin: boolean
81
+ iat: number
82
+ exp: number
83
+ scopes?: string[]
33
84
  }
34
85
 
35
- const mocks = [userMock]
86
+ describe("UserQuery component - Dynamic ORCID Loading", () => {
87
+ const mockedIsValidOrcid = vi.mocked(isValidOrcid)
88
+ const mockedGetProfile = vi.mocked(getProfile)
89
+ const mockedIsAdmin = vi.mocked(isAdmin)
90
+ const mockedUseCookies = vi.mocked(useCookies)
91
+ const mockedUseUser = vi.mocked(useUser)
92
+
93
+ let testOrcid: string
36
94
 
37
- describe("UserQuery component", () => {
38
- it("displays the ORCID on the page for a valid ORCID", async () => {
95
+ beforeEach(() => {
96
+ vi.clearAllMocks()
97
+ vi.resetAllMocks()
98
+ mockedIsValidOrcid.mockReturnValue(true)
99
+
100
+ mockedGetProfile.mockReturnValue({
101
+ sub: "11111",
102
+ admin: false,
103
+ iat: Date.now(),
104
+ exp: Date.now() + (1000 * 60 * 60),
105
+ scopes: [],
106
+ })
107
+
108
+ mockedIsAdmin.mockReturnValue(false)
109
+ mockedUseCookies.mockReturnValue([{}, vi.fn(), vi.fn()])
110
+ testOrcid = generateRandomValidOrcid()
111
+
112
+ mockedUseUser.mockImplementation((orcidParam: string) => {
113
+ const dynamicUser: User = {
114
+ id: orcidParam,
115
+ name: `Mock User for ${orcidParam}`,
116
+ location: "Dynamic Location",
117
+ institution: "Dynamic Institution",
118
+ email: `${orcidParam}@example.com`,
119
+ avatar: "https://dummyimage.com/200x200/000/fff",
120
+ orcid: orcidParam,
121
+ links: [],
122
+ }
123
+ return {
124
+ user: dynamicUser,
125
+ loading: false,
126
+ error: undefined,
127
+ }
128
+ })
129
+ })
130
+
131
+ it("loads the page and displays user data for a valid ORCID from the URL", async () => {
39
132
  render(
40
- <MockedProvider mocks={mocks} addTypename={true}>
41
- <MemoryRouter initialEntries={[`/user/${validOrcid}`]}>
133
+ <MockedProvider mocks={[]} addTypename={true}>
134
+ <MemoryRouter initialEntries={[`/user/${testOrcid}`]}>
42
135
  <Routes>
43
136
  <Route path="/user/:orcid" element={<UserQuery />} />
44
137
  </Routes>
@@ -46,26 +139,28 @@ describe("UserQuery component", () => {
46
139
  </MockedProvider>,
47
140
  )
48
141
 
49
- await waitFor(() =>
50
- expect(screen.queryByText("Loading...")).not.toBeInTheDocument()
51
- )
52
-
53
- expect(screen.getByText(validOrcid)).toBeInTheDocument()
142
+ expect(screen.getByText(`${testOrcid}`)).toBeInTheDocument()
54
143
  })
55
144
 
56
- it("shows 404 page for invalid ORCID", async () => {
145
+ it("displays 404 if the ORCID in the URL is invalid", async () => {
146
+ const invalidOrcid = "invalid-orcid-string"
147
+
148
+ mockedUseUser.mockReturnValue({
149
+ user: undefined,
150
+ loading: false,
151
+ error: undefined,
152
+ })
57
153
  render(
58
154
  <MockedProvider mocks={[]} addTypename={true}>
59
- <MemoryRouter initialEntries={[`/user/invalid-orcid`]}>
155
+ <MemoryRouter initialEntries={[`/user/${invalidOrcid}`]}>
60
156
  <Routes>
61
157
  <Route path="/user/:orcid" element={<UserQuery />} />
62
158
  </Routes>
63
159
  </MemoryRouter>
64
160
  </MockedProvider>,
65
161
  )
66
-
67
- await waitFor(() => screen.getByText(/404/i))
68
-
69
- expect(screen.getByText(/404/i)).toBeInTheDocument()
162
+ expect(
163
+ screen.getByText(/404: The page you are looking for does not exist./i),
164
+ ).toBeInTheDocument()
70
165
  })
71
166
  })