Skip to content

Commit

Permalink
Merge pull request #1353 from nickgros/SWC-7064b
Browse files Browse the repository at this point in the history
  • Loading branch information
nickgros authored Nov 5, 2024
2 parents 0dba1f5 + bb65ba5 commit 30072f5
Show file tree
Hide file tree
Showing 7 changed files with 559 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export function getUseMutationMock<TData, TError, TVariables>(
isPaused: false,
isSuccess: false,
mutate: jest.fn(),
mutateAsync: jest.fn(),
mutateAsync: jest.fn().mockResolvedValue(data),
reset: jest.fn(),
status: 'idle',
variables: undefined,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { SynapseClientError } from '@sage-bionetworks/synapse-client'
import {
MOCK_FOLDER_ID,
mockFolderEntity,
} from '../../../mocks/entity/mockEntity'
import mockFileEntity, {
MOCK_FILE_ENTITY_ID,
} from '../../../mocks/entity/mockFileEntity'
import { MOCK_CONTEXT_VALUE } from '../../../mocks/MockSynapseContext'
import { getFileEntityIdWithSameName } from './getFileEntityIdWithSameName'

const lookupEntitySpy = jest.spyOn(
MOCK_CONTEXT_VALUE.synapseClient.entityServicesClient,
'postRepoV1EntityChild',
)
const getEntitySpy = jest.spyOn(
MOCK_CONTEXT_VALUE.synapseClient.entityServicesClient,
'getRepoV1EntityId',
)

describe('getFileEntityIdWithSameName', () => {
beforeEach(() => {
jest.clearAllMocks()
})

test('Entity does not exist', async () => {
const name = 'file.txt'
const parentId = 'syn123'

lookupEntitySpy.mockRejectedValue(
new SynapseClientError(
404,
'Not found',
expect.getState().currentTestName!,
),
)

const result = await getFileEntityIdWithSameName(
name,
parentId,
MOCK_CONTEXT_VALUE.synapseClient,
)

expect(result).toBeNull()

expect(lookupEntitySpy).toHaveBeenCalledTimes(1)
expect(lookupEntitySpy).toHaveBeenCalledWith({
entityLookupRequest: { parentId, entityName: name },
})

expect(getEntitySpy).not.toHaveBeenCalled()
})

test('Entity exists', async () => {
const name = 'file.txt'
const parentId = 'syn123'

lookupEntitySpy.mockResolvedValue({ id: MOCK_FILE_ENTITY_ID })
getEntitySpy.mockResolvedValue(mockFileEntity.entity)

const result = await getFileEntityIdWithSameName(
name,
parentId,
MOCK_CONTEXT_VALUE.synapseClient,
)

expect(result).toBe(MOCK_FILE_ENTITY_ID)

expect(lookupEntitySpy).toHaveBeenCalledTimes(1)
expect(lookupEntitySpy).toHaveBeenCalledWith({
entityLookupRequest: { parentId, entityName: name },
})

expect(getEntitySpy).toHaveBeenCalledTimes(1)
expect(getEntitySpy).toHaveBeenCalledWith({ id: MOCK_FILE_ENTITY_ID })
})

test('Entity exists but is not a file', async () => {
const name = 'file.txt'
const parentId = 'syn123'

lookupEntitySpy.mockResolvedValue({ id: MOCK_FOLDER_ID })
getEntitySpy.mockResolvedValue(mockFolderEntity)

await expect(
getFileEntityIdWithSameName(
name,
parentId,
MOCK_CONTEXT_VALUE.synapseClient,
'This is additional context for the error message.',
),
).rejects.toThrow(
`A(n) Folder named "file.txt" already exists in this location (syn123). This is additional context for the error message.`,
)

expect(lookupEntitySpy).toHaveBeenCalledTimes(1)
expect(lookupEntitySpy).toHaveBeenCalledWith({
entityLookupRequest: { parentId, entityName: name },
})

expect(getEntitySpy).toHaveBeenCalledTimes(1)
expect(getEntitySpy).toHaveBeenCalledWith({ id: MOCK_FOLDER_ID })
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { SynapseClient } from '@sage-bionetworks/synapse-client'
import { allowNotFoundError } from '../../../synapse-client/SynapseClientUtils'
import {
convertToEntityType,
entityTypeToFriendlyName,
} from '../../functions/EntityTypeUtils'

/**
* Gets the ID of the file entity with the given name whose parent has the given ID.
*
* @param name The name of the entity to find.
* @param parentId The ID of the parent that the found entity must have.
* @return The ID of the file entity with the given name and parent ID, or null if the entity does not exist
* @throws Error If an entity with given name and parent ID was found, but that entity
* was not a File Entity.
*/
export async function getFileEntityIdWithSameName(
name: string,
parentId: string,
synapseClient: SynapseClient,
errorContext?: string,
) {
const result =
(
await allowNotFoundError(() =>
synapseClient.entityServicesClient.postRepoV1EntityChild({
entityLookupRequest: {
parentId: parentId,
entityName: name,
},
}),
)
)?.id ?? null

if (result == null) {
return result
}

const entity = await synapseClient.entityServicesClient.getRepoV1EntityId({
id: result,
})

if (entity.concreteType != 'org.sagebionetworks.repo.model.FileEntity') {
const typeOfExistingEntity = convertToEntityType(entity.concreteType)
throw new Error(
`A(n) ${entityTypeToFriendlyName(
typeOfExistingEntity,
)} named "${name}" already exists in this location (${parentId}).${
errorContext ? ` ${errorContext}` : ''
}`,
)
}
return entity.id!
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import { SynapseClientError } from '@sage-bionetworks/synapse-client'
import { renderHook as _renderHook } from '@testing-library/react'
import {
MOCK_FOLDER_ID,
mockFolderEntity,
} from '../../../mocks/entity/mockEntity'
import mockFileEntity, {
MOCK_FILE_ENTITY_ID,
} from '../../../mocks/entity/mockFileEntity'
import { MOCK_CONTEXT_VALUE } from '../../../mocks/MockSynapseContext'
import SynapseClient from '../../../synapse-client/index'
import { createWrapper } from '../../../testutils/TestingLibraryUtils'
import { useCreateFolderPath } from './useCreateFolderPath'

const lookupEntitySpy = jest.spyOn(
MOCK_CONTEXT_VALUE.synapseClient.entityServicesClient,
'postRepoV1EntityChild',
)
const getEntitySpy = jest.spyOn(
MOCK_CONTEXT_VALUE.synapseClient.entityServicesClient,
'getRepoV1EntityId',
)
const createEntitySpy = jest.spyOn(SynapseClient, 'createEntity')

describe('useCreateFolderPath', () => {
function renderHook() {
return _renderHook(() => useCreateFolderPath(), {
wrapper: createWrapper(),
})
}
beforeEach(() => {
jest.clearAllMocks()
})
test('existing folder', async () => {
lookupEntitySpy.mockResolvedValue({ id: MOCK_FOLDER_ID })
getEntitySpy.mockResolvedValue(mockFolderEntity)

const { result: hook } = renderHook()

const result = await hook.current.mutateAsync({
parentId: 'syn123',
path: ['folder'],
})

expect(result).toEqual(MOCK_FOLDER_ID)

expect(lookupEntitySpy).toHaveBeenCalledTimes(1)
expect(getEntitySpy).toHaveBeenCalledTimes(1)
expect(createEntitySpy).not.toHaveBeenCalled()
})

test('create a new folder', async () => {
lookupEntitySpy.mockRejectedValue(
new SynapseClientError(
404,
'Not found',
expect.getState().currentTestName!,
),
)
createEntitySpy.mockResolvedValue(mockFolderEntity)

const { result: hook } = renderHook()

const result = await hook.current.mutateAsync({
parentId: 'syn123',
path: ['folder'],
})

expect(result).toEqual(MOCK_FOLDER_ID)

expect(lookupEntitySpy).toHaveBeenCalledTimes(1)
expect(getEntitySpy).not.toHaveBeenCalled()
expect(createEntitySpy).toHaveBeenCalledTimes(1)
expect(createEntitySpy).toHaveBeenCalledWith(
{
concreteType: 'org.sagebionetworks.repo.model.Folder',
name: 'folder',
parentId: 'syn123',
},
MOCK_CONTEXT_VALUE.accessToken,
)
})

test('empty path', async () => {
const { result: hook } = renderHook()

const result = await hook.current.mutateAsync({
parentId: 'syn123',
path: [],
})

expect(result).toEqual('syn123')
})

test('path with multiple folders', async () => {
const existingFolderId = 'syn456'
const createdFolderId = 'syn789'

lookupEntitySpy.mockImplementation(args => {
if (args.entityLookupRequest.entityName == 'parentFolder') {
return Promise.resolve({ id: existingFolderId })
}
throw new SynapseClientError(
404,
'Not found',
expect.getState().currentTestName!,
)
})
createEntitySpy.mockResolvedValue({
...mockFolderEntity,
name: 'childFolder',
id: createdFolderId,
})

const { result: hook } = renderHook()

const result = await hook.current.mutateAsync({
parentId: 'syn123',
path: ['parentFolder', 'childFolder'],
})

expect(result).toEqual(createdFolderId)

expect(lookupEntitySpy).toHaveBeenCalledTimes(2)
expect(getEntitySpy).toHaveBeenCalledTimes(1)
expect(createEntitySpy).toHaveBeenCalledTimes(1)
expect(createEntitySpy).toHaveBeenCalledWith(
{
concreteType: 'org.sagebionetworks.repo.model.Folder',
name: 'childFolder',
parentId: existingFolderId,
},
MOCK_CONTEXT_VALUE.accessToken,
)
})

test('existing entity is not a folder', async () => {
lookupEntitySpy.mockResolvedValue({ id: MOCK_FILE_ENTITY_ID })
getEntitySpy.mockResolvedValue(mockFileEntity.entity)

const { result: hook } = renderHook()

await expect(
hook.current.mutateAsync({
parentId: 'syn123',
path: ['some_name'],
}),
).rejects.toThrow(
`A(n) File named "some_name" already exists in this location (syn123). A folder could not be created.`,
)

expect(lookupEntitySpy).toHaveBeenCalledTimes(1)
expect(getEntitySpy).toHaveBeenCalledTimes(1)
expect(createEntitySpy).not.toHaveBeenCalled()
})

test('createEntity fails', async () => {
lookupEntitySpy.mockRejectedValue(
new SynapseClientError(
404,
'Not found',
expect.getState().currentTestName!,
),
)
createEntitySpy.mockRejectedValue(
new SynapseClientError(
403,
'Forbidden',
expect.getState().currentTestName!,
),
)

const { result: hook } = renderHook()
await expect(
hook.current.mutateAsync({
parentId: 'syn123',
path: ['folder'],
}),
).rejects.toThrow(`Forbidden`)

expect(lookupEntitySpy).toHaveBeenCalledTimes(1)
expect(getEntitySpy).not.toHaveBeenCalled()
expect(createEntitySpy).toHaveBeenCalledTimes(1)
expect(createEntitySpy).toHaveBeenCalledWith(
{
concreteType: 'org.sagebionetworks.repo.model.Folder',
name: 'folder',
parentId: 'syn123',
},
MOCK_CONTEXT_VALUE.accessToken,
)
})
})
Loading

0 comments on commit 30072f5

Please sign in to comment.