fix: issues related to Auth test suite

This commit is contained in:
Alessio Gravili
2024-03-18 15:30:55 -04:00
parent 0a8f400a59
commit 26df916421
12 changed files with 55 additions and 29 deletions

View File

@@ -66,6 +66,7 @@ export const DefaultEditView: React.FC = () => {
const { reportUpdate } = useDocumentEvents()
const {
admin: { user: userSlug },
collections,
globals,
routes: { admin: adminRoute, api: apiRoute },
@@ -108,9 +109,9 @@ export const DefaultEditView: React.FC = () => {
updatedAt: json?.result?.updatedAt || new Date().toISOString(),
})
// If we're editing the doc of the logged in user,
// If we're editing the doc of the logged-in user,
// Refresh the cookie to get new permissions
if (user && collectionSlug === user?.collection && id === user?.id) {
if (user && collectionSlug === userSlug && id === user.id) {
void refreshCookieAsync()
}
@@ -135,8 +136,7 @@ export const DefaultEditView: React.FC = () => {
id,
entitySlug,
collectionSlug,
user?.collection,
user?.id,
user,
getVersions,
getDocPermissions,
isEditing,

View File

@@ -2,13 +2,13 @@ import jwt from 'jsonwebtoken'
import type { Collection } from '../../collections/config/types.js'
import type { PayloadRequest } from '../../types/index.js'
import type { User } from '../types.js'
import type { ClientUser, User } from '../types.js'
export type Result = {
export type MeOperationResult = {
collection?: string
exp?: number
token?: string
user?: User
user?: ClientUser
}
export type Arguments = {
@@ -21,8 +21,8 @@ export const meOperation = async ({
collection,
currentToken,
req,
}: Arguments): Promise<Result> => {
let result: Result = {
}: Arguments): Promise<MeOperationResult> => {
let result: MeOperationResult = {
user: null,
}

View File

@@ -62,12 +62,18 @@ export type Permissions = {
}
export type User = {
[key: string]: unknown
[key: string]: any // This NEEDS to be an any, otherwise it breaks the Omit for ClientUser below
collection: string
email: string
id: string
}
/**
* `collection` is not available one the client. It's only available on the server (req.user)
* On the client, you can access the collection via config.admin.user. Config can be accessed using the useConfig() hook
*/
export type ClientUser = Omit<User, 'collection'>
type GenerateVerifyEmailHTML = (args: {
req: PayloadRequest
token: string

View File

@@ -7,7 +7,7 @@ import type {
CustomSaveButtonProps,
CustomSaveDraftButtonProps,
} from '../../admin/types.js'
import type { Auth, IncomingAuthType, User } from '../../auth/types.js'
import type { Auth, ClientUser, IncomingAuthType } from '../../auth/types.js'
import type {
Access,
EditConfig,
@@ -270,7 +270,7 @@ export type CollectionAdminOptions = {
/**
* Exclude the collection from the admin nav and routes
*/
hidden?: ((args: { user: User }) => boolean) | boolean
hidden?: ((args: { user: ClientUser }) => boolean) | boolean
/**
* Hide the API URL within the Edit view
*/

View File

@@ -3,6 +3,7 @@ export type * from '../admin/types.js'
export type * from '../uploads/types.js'
export type { DocumentPermissions, FieldPermissions } from '../auth/index.js'
export type { MeOperationResult } from '../auth/operations/me.js'
export type {
CollapsedPreferences,

View File

@@ -1,4 +1,4 @@
import type { User } from 'payload/auth'
import type { ClientUser } from 'payload/auth'
import type { SanitizedCollectionConfig } from 'payload/types'
import { useAuth, useConfig } from '@payloadcms/ui'
@@ -6,7 +6,7 @@ import * as React from 'react'
type options = {
uploads: boolean
user: User
user: ClientUser
}
type FilteredCollectionsT = (

View File

@@ -1,6 +1,6 @@
'use client'
import type { User } from 'payload/auth'
import type { ClientUser } from 'payload/auth'
import type { SanitizedCollectionConfig } from 'payload/types'
import { useAuth, useConfig } from '@payloadcms/ui/providers'
@@ -8,7 +8,7 @@ import * as React from 'react'
type options = {
uploads: boolean
user: User
user: ClientUser
}
type FilteredCollectionsT = (

View File

@@ -11,17 +11,17 @@ import { useForm } from '../Form/context.js'
import './index.scss'
const Label: React.FC<LabelProps> = (props) => {
const { htmlFor: htmlForFromProps, label, required = false } = props
const { htmlFor: htmlForFromProps, label: labelFromProps, required = false } = props
const { uuid } = useForm()
const { path } = useFieldProps()
const htmlFor = htmlForFromProps || generateFieldID(path, uuid)
const { i18n } = useTranslation()
if (label) {
if (labelFromProps) {
return (
<label className="field-label" htmlFor={htmlFor}>
{getTranslation(label, i18n)}
{getTranslation(labelFromProps, i18n)}
{required && <span className="required">*</span>}
</label>
)

View File

@@ -1,5 +1,6 @@
'use client'
import type { Permissions, User } from 'payload/auth'
import type { ClientUser, Permissions } from 'payload/auth'
import type { MeOperationResult } from 'payload/types.js'
import * as facelessUIImport from '@faceless-ui/modal'
import { usePathname, useRouter } from 'next/navigation.js'
@@ -24,7 +25,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
const { useModal } = facelessUIImport
const { searchParams } = useSearchParams()
const [user, setUser] = useState<User | null>()
const [user, setUser] = useState<ClientUser | null>()
const [tokenInMemory, setTokenInMemory] = useState<string>()
const [tokenExpiration, setTokenExpiration] = useState<number>()
const pathname = usePathname()
@@ -94,6 +95,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
if (request.status === 200) {
const json = await request.json()
setUser(json.user)
setTokenAndExpiration(json)
} else {
setUser(null)
@@ -117,7 +119,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
)
const refreshCookieAsync = useCallback(
async (skipSetUser?: boolean): Promise<User> => {
async (skipSetUser?: boolean): Promise<ClientUser> => {
try {
const request = await requests.post(`${serverURL}${api}/${userSlug}/refresh-token`, {
headers: {
@@ -187,10 +189,11 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
})
if (request.status === 200) {
const json = await request.json()
const json: MeOperationResult = await request.json()
if (json?.user) {
setUser(json.user)
if (json?.token) {
setTokenAndExpiration(json)
}
@@ -317,4 +320,4 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
)
}
export const useAuth = <T = User,>(): AuthContext<T> => useContext(Context) as AuthContext<T>
export const useAuth = <T = ClientUser,>(): AuthContext<T> => useContext(Context) as AuthContext<T>

View File

@@ -1,11 +1,11 @@
import type { Permissions, User } from 'payload/auth'
import type { ClientUser, Permissions } from 'payload/auth'
export type AuthContext<T = User> = {
export type AuthContext<T = ClientUser> = {
fetchFullUser: () => Promise<void>
logOut: () => void
permissions?: Permissions
refreshCookie: (forceRefresh?: boolean) => void
refreshCookieAsync: () => Promise<User>
refreshCookieAsync: () => Promise<ClientUser>
refreshPermissions: () => Promise<void>
setPermissions: (permissions: Permissions) => void
setUser: (user: T) => void

View File

@@ -17,6 +17,9 @@ export default buildConfigWithDefaults({
},
collections: [
{
admin: {
useAsTitle: 'custom',
},
slug,
auth: {
cookies: {
@@ -198,6 +201,16 @@ export default buildConfigWithDefaults({
},
fields: [],
},
{
slug: 'relationsCollection',
fields: [
{
name: 'rel',
type: 'relationship',
relationTo: 'users',
},
],
},
],
onInit: async (payload) => {
await payload.create({

View File

@@ -4,7 +4,8 @@ import { expect, test } from '@playwright/test'
import path from 'path'
import { fileURLToPath } from 'url'
import payload from '../../packages/payload/src/index.js'
import type { Payload } from '../../packages/payload/src/index.js'
import { initPageConsoleErrorCatch, login, saveDocAndAssert } from '../helpers.js'
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
import { initPayloadE2E } from '../helpers/initPayloadE2E.js'
@@ -12,6 +13,7 @@ import config from './config.js'
import { apiKeysSlug, slug } from './shared.js'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
let payload: Payload
/**
* TODO: Auth
@@ -33,7 +35,8 @@ describe('auth', () => {
let apiURL: string
beforeAll(async ({ browser }) => {
;({ serverURL } = await initPayloadE2E({ config, dirname }))
;({ serverURL, payload } = await initPayloadE2E({ config, dirname }))
apiURL = `${serverURL}/api`
url = new AdminUrlUtil(serverURL, slug)
const context = await browser.newContext()