Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions api/src/additional-findings/data-source.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { loadAdditionalFindingsByDomainId, loadTop25Reports } from './loaders'
import { loadAdditionalFindingsByDomainId } from './loaders'

export class AdditionalFindingsDataSource {
constructor({ query, userKey, i18n, language }) {
this.getByDomainId = loadAdditionalFindingsByDomainId({ query, userKey, i18n })
this.getTop25Reports = loadTop25Reports({ query, userKey, i18n, language })
constructor({ query, userKey, cleanseInput, i18n }) {
this.getByDomainId = loadAdditionalFindingsByDomainId({ query, userKey, cleanseInput, i18n })
}
}
23 changes: 23 additions & 0 deletions api/src/additional-findings/input/additional-finding-filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { GraphQLInputObjectType } from 'graphql'

import { ComparisonEnums, AdditionalFindingFilterCategory } from '../../enums'
import { FilterValueScalar } from '../../scalars/filter-value'

export const additionalFindingFilter = new GraphQLInputObjectType({
name: 'AdditionalFindingFilter',
description: 'This object is used to provide filtering options when querying additional findings.',
fields: () => ({
filterCategory: {
type: AdditionalFindingFilterCategory,
description: 'Category of filter to be applied.',
},
comparison: {
type: ComparisonEnums,
description: 'First value equals or does not equal second value.',
},
filterValue: {
type: FilterValueScalar,
description: 'Additional finding filter value.',
},
}),
})
18 changes: 18 additions & 0 deletions api/src/additional-findings/input/additional-finding-order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { GraphQLInputObjectType, GraphQLNonNull } from 'graphql'

import { OrderDirection, AdditionalFindingOrderField } from '../../enums'

export const additionalFindingOrder = new GraphQLInputObjectType({
name: 'AdditionalFindingOrder',
description: 'Ordering options for additional findings.',
fields: () => ({
field: {
type: new GraphQLNonNull(AdditionalFindingOrderField),
description: 'The field to order additional findings by.',
},
direction: {
type: new GraphQLNonNull(OrderDirection),
description: 'The ordering direction.',
},
}),
})
2 changes: 2 additions & 0 deletions api/src/additional-findings/input/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './cvd-enrollment-options'
export * from './additional-finding-order'
export * from './additional-finding-filter'
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,31 @@ describe('loadAdditionalFindingsByDomainId', () => {
it('throws an error when domainId is not provided', async () => {
const loadAdditionalFindingsByDomainId =
require('../load-additional-findings-by-domain-id').loadAdditionalFindingsByDomainId
const func = loadAdditionalFindingsByDomainId({ query: jest.fn(), userKey: 'userKey', i18n })
const func = loadAdditionalFindingsByDomainId({
query: jest.fn(),
userKey: 'userKey',
cleanseInput: jest.fn((input) => input),
i18n,
})

await expect(func({ limit: 10 })).rejects.toThrow(
"You must provide a `domainId` to retrieve a domain's additional findings.",
)
})

it('throws an error when limit is not provided', async () => {
const loadAdditionalFindingsByDomainId =
require('../load-additional-findings-by-domain-id').loadAdditionalFindingsByDomainId
const func = loadAdditionalFindingsByDomainId({
query: jest.fn(),
userKey: 'userKey',
cleanseInput: jest.fn((input) => input),
i18n,
})

await expect(func({})).rejects.toThrow("You must provide a `domainId` to retrieve a domain's additional findings.")
await expect(func({ domainId: 'domainId' })).rejects.toThrow(
'You must provide a `limit` value to properly paginate additional findings.',
)
})

it('throws an error when a database error occurs', async () => {
Expand All @@ -31,9 +53,14 @@ describe('loadAdditionalFindingsByDomainId', () => {
})
const loadAdditionalFindingsByDomainId =
require('../load-additional-findings-by-domain-id').loadAdditionalFindingsByDomainId
const func = loadAdditionalFindingsByDomainId({ query, userKey: 'userKey', i18n })
const func = loadAdditionalFindingsByDomainId({
query,
userKey: 'userKey',
cleanseInput: jest.fn((input) => input),
i18n,
})

await expect(func({ domainId: 'domainId' })).rejects.toThrow(
await expect(func({ domainId: 'domainId', limit: 10 })).rejects.toThrow(
'Unable to load additional findings. Please try again.',
)
})
Expand All @@ -47,23 +74,114 @@ describe('loadAdditionalFindingsByDomainId', () => {
const query = jest.fn(() => cursor)
const loadAdditionalFindingsByDomainId =
require('../load-additional-findings-by-domain-id').loadAdditionalFindingsByDomainId
const func = loadAdditionalFindingsByDomainId({ query, userKey: 'userKey', i18n })
const func = loadAdditionalFindingsByDomainId({
query,
userKey: 'userKey',
cleanseInput: jest.fn((input) => input),
i18n,
})

await expect(func({ domainId: 'domainId' })).rejects.toThrow(
await expect(func({ domainId: 'domainId', limit: 10 })).rejects.toThrow(
'Unable to load additional findings. Please try again.',
)
})

it('returns the finding when everything is correct', async () => {
const finding = { id: 'findingId' }
const cursor = { next: jest.fn(() => finding) }
it('returns a connection when everything is correct', async () => {
const finding = { _key: '1', source: 'scanner-a' }
const cursor = {
next: jest.fn(() => ({
findings: [finding],
totalCount: 1,
hasMoreRelayPage: false,
hasReversePage: false,
})),
}
const query = jest.fn(() => cursor)
const loadAdditionalFindingsByDomainId =
require('../load-additional-findings-by-domain-id').loadAdditionalFindingsByDomainId
const func = loadAdditionalFindingsByDomainId({
query,
userKey: 'userKey',
cleanseInput: jest.fn((input) => input),
i18n,
})

const result = await func({ domainId: 'domainId', limit: 10 })

expect(result.totalCount).toEqual(1)
expect(result.edges).toHaveLength(1)
expect(result.edges[0].node).toEqual(finding)
expect(result.pageInfo).toEqual({
hasPreviousPage: false,
hasNextPage: false,
startCursor: result.edges[0].cursor,
endCursor: result.edges[0].cursor,
})
})

it('returns an empty connection when there are no findings', async () => {
const cursor = {
next: jest.fn(() => ({
findings: [],
totalCount: 0,
hasMoreRelayPage: false,
hasReversePage: false,
})),
}
const query = jest.fn(() => cursor)
const loadAdditionalFindingsByDomainId =
require('../load-additional-findings-by-domain-id').loadAdditionalFindingsByDomainId
const func = loadAdditionalFindingsByDomainId({
query,
userKey: 'userKey',
cleanseInput: jest.fn((input) => input),
i18n,
})

const result = await func({ domainId: 'domainId', limit: 10 })

expect(result).toEqual({
edges: [],
totalCount: 0,
pageInfo: {
hasPreviousPage: false,
hasNextPage: false,
startCursor: null,
endCursor: null,
},
})
})

it('accepts AND filters and orderBy arguments', async () => {
const cursor = {
next: jest.fn(() => ({
findings: [{ _key: '2', source: 'scanner-b', severity: 'high' }],
totalCount: 1,
hasMoreRelayPage: false,
hasReversePage: false,
})),
}
const query = jest.fn(() => cursor)
const loadAdditionalFindingsByDomainId =
require('../load-additional-findings-by-domain-id').loadAdditionalFindingsByDomainId
const func = loadAdditionalFindingsByDomainId({ query, userKey: 'userKey', i18n })
const func = loadAdditionalFindingsByDomainId({
query,
userKey: 'userKey',
cleanseInput: jest.fn((input) => input),
i18n,
})

const result = await func({ domainId: 'domainId' })
const result = await func({
domainId: 'domainId',
limit: 10,
orderBy: { field: 'severity', direction: 'DESC' },
filters: [
{ filterCategory: 'source', comparison: '==', filterValue: 'scanner-b' },
{ filterCategory: 'severity', comparison: '==', filterValue: 'high' },
],
})

expect(result).toEqual(finding)
expect(query).toHaveBeenCalled()
expect(result.edges).toHaveLength(1)
})
})
1 change: 0 additions & 1 deletion api/src/additional-findings/loaders/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from './load-additional-findings-by-domain-id'
export * from './load-top-25-reports'
Loading