Skip to content

Commit

Permalink
test(validation): add failing slug test; configure jest
Browse files Browse the repository at this point in the history
  • Loading branch information
ricokahler committed Aug 27, 2021
1 parent 9062b84 commit 9522cc9
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 6 deletions.
17 changes: 17 additions & 0 deletions packages/@sanity/validation/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const path = require('path')

/** @type {import('@jest/types').Config.InitialOptions} */
const config = {
verbose: true,
moduleNameMapper: {
'@sanity/validation': path.resolve(__dirname, './src'),
'part:@sanity/base/schema-creator': path.resolve(__dirname, '../base/lib/schema/createSchema'),
'part:@sanity/form-builder/input/legacy-date/schema?': path.resolve(
__dirname,
'./test/nullExport'
),
'part:@sanity/base/client': path.resolve(__dirname, './test/mockClient'),
},
}

module.exports = config
5 changes: 0 additions & 5 deletions packages/@sanity/validation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,5 @@
"@sanity/types": "2.17.0",
"date-fns": "^2.16.1",
"lodash": "^4.17.15"
},
"jest": {
"verbose": true,
"collectCoverage": true,
"testURL": "http://localhost/"
}
}
94 changes: 93 additions & 1 deletion packages/@sanity/validation/test/infer.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/// <reference types="@sanity/types/parts" />

import Schema from '@sanity/schema'
import {ObjectSchemaType, Rule} from '@sanity/types'
import {ObjectSchemaType, Rule, SanityDocument} from '@sanity/types'
import createSchema from 'part:@sanity/base/schema-creator'
import client from 'part:@sanity/base/client'
import inferFromSchema from '../src/inferFromSchema'
import validateDocument from '../src/validateDocument'

describe('schema validation inference', () => {
describe('object with `options.list` and `value` field', () => {
Expand Down Expand Up @@ -82,6 +87,93 @@ describe('schema validation inference', () => {
).toEqual([{flag: 'type', constraint: 'String'}])
})
})
describe('slug validation', () => {
const slugField = {
type: 'document',
name: 'documentWithSlug',
title: 'Document with Slug',
fields: [
{
name: 'slugField',
type: 'slug',
},
],
}

const schema = createSchema({
types: [slugField],
})

const mockDocument: SanityDocument = {
_id: 'mockDocument',
_type: 'documentWithSlug',
slugField: {current: 'example-value'},
_createdAt: '2021-08-26T18:47:55.497Z',
_updatedAt: '2021-08-26T18:47:55.497Z',
_rev: 'example-rev',
}

afterEach(() => {
;(client.fetch as jest.Mock).mockReset()
})

test('slug is valid if uniqueness queries returns true', async () => {
;(client.fetch as jest.Mock).mockImplementation(() =>
Promise.resolve(
// return true to mock a unique result (valid)
true
)
)
await expect(validateDocument(mockDocument, schema)).resolves.toEqual([])

expect(client.fetch).toHaveBeenCalledTimes(1)
expect((client.fetch as jest.Mock).mock.calls[0]).toEqual([
'!defined(*[_type == $docType && !(_id in [$draft, $published]) && slugField.current == $slug][0]._id)',
{
docType: 'documentWithSlug',
draft: 'drafts.mockDocument',
published: 'mockDocument',
slug: 'example-value',
},
{
tag: 'validation.slug-is-unique',
},
])
})

test('slug is invalid if uniqueness queries returns false', async () => {
;(client.fetch as jest.Mock).mockReset()
;(client.fetch as jest.Mock).mockImplementation(() =>
Promise.resolve(
// return false to mock a non-unique result (invalid)
false
)
)

await expect(validateDocument(mockDocument, schema)).resolves.toMatchObject([
{
type: 'validation',
path: ['slugField'],
level: 'error',
item: {message: 'Slug is already in use', paths: []},
},
])

expect(client.fetch).toHaveBeenCalledTimes(1)
expect((client.fetch as jest.Mock).mock.calls[0]).toEqual([
'!defined(*[_type == $docType && !(_id in [$draft, $published]) && slugField.current == $slug][0]._id)',
{
docType: 'documentWithSlug',
draft: 'drafts.mockDocument',
published: 'mockDocument',
slug: 'example-value',
},
{
tag: 'validation.slug-is-unique',
},
])
})
})
})

async function expectNoError(validations: Rule[], value: unknown) {
Expand Down
37 changes: 37 additions & 0 deletions packages/@sanity/validation/test/mockClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type {SanityClient} from '@sanity/client'

/**
* this mock client is used via the `moduleNameMapper` in `jest.config.js`
*
* you can import the part and use the mock from each method like so:
*
* ```ts
* import client from 'part:@sanity/base/client'
*
* afterEach(() => {
* ;(client.fetch as jest.Mock).mockReset();
* })
*
* describe('someFeatureThatUsesTheClient', () => {
*
* test('some test', async () => {
* // set up the mock
* ;(client.fetch as jest.Mock).mockImplementation(() => Promise.resolve('example'))
*
* // do you test
* // e.g. validateDocument()
*
* expect(client.fetch).toHaveBeenCalledTime(1)
* expect((client.mock as jest.Mock).mock.calls).toMatchObject({
* // ...
* })
* })
* })
* ```
*/
const client = ({
fetch: jest.fn(),
withConfig: jest.fn(() => client),
} as unknown) as SanityClient

module.exports = client
3 changes: 3 additions & 0 deletions packages/@sanity/validation/test/nullExport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// used to mock out a part
// see the jest config
module.exports = null

0 comments on commit 9522cc9

Please sign in to comment.