Skip to content

Commit

Permalink
Add tests for pluginRegistry
Browse files Browse the repository at this point in the history
Co-authored-by: Mark Wubben <[email protected]>
  • Loading branch information
bunysae and novemberborn committed Apr 4, 2020
1 parent 9f7852f commit 1638c09
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 5 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"eslint-plugin-security": "^1.4.0",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-unicorn": "^17.2.0",
"nyc": "^15.0.0"
"nyc": "^15.0.0",
"proxyquire": "^2.1.3"
},
"nyc": {
"reporter": [
Expand Down
45 changes: 45 additions & 0 deletions test/fixtures/customErrorPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict'
class CustomError extends Error {
constructor (message, code) {
super(message)
this.code = code
this.name = 'CustomError'
}
}

exports.CustomError = CustomError

exports.factory = function ({ DescribedMixin, DeserializedMixin, ObjectValue }) {
const tag = Symbol.for('customError')

class DescribedErrorValue extends DescribedMixin(ObjectValue) {
createPropertyRecursor () {
let i = 0
return {
size: 1,
next: () => {
if (i === 1) {
return null
}
i++
return this.describeProperty('code', this.describeAny(this.value.code))
},
}
}
}

Object.defineProperty(DescribedErrorValue.prototype, 'tag', { value: tag })

const DeserializedErrorValue = DeserializedMixin(ObjectValue)
Object.defineProperty(DeserializedErrorValue.prototype, 'tag', { value: tag })

return {
describe (props) {
return new DescribedErrorValue(props)
},
deserialize (state, recursor) {
return new DeserializedErrorValue(state, recursor)
},
tag,
}
}
23 changes: 23 additions & 0 deletions test/format.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const test = require('ava')

const { format: _format } = require('../lib/format')
const { theme, normalizedTheme, checkThemeUsage } = require('./_instrumentedTheme')
const customErrorPlugin = require('./fixtures/customErrorPlugin')

const format = value => _format(value, { theme })
test.after(checkThemeUsage)
Expand Down Expand Up @@ -408,3 +409,25 @@ test('shows string tag if object has no constructor', t => {
test('formats global', t => {
t.snapshot(format(global))
})

test('format with given plugin', t => {
const plugins = [
{
name: 'CustomError',
apiVersion: 1,
register: props => {
const { describe } = customErrorPlugin.factory(props)
return function (value) {
if (value.name === 'CustomError') {
return describe
}
}
},
},
]

const actual1 = _format(new customErrorPlugin.CustomError('plugin formatter', 'PLUGIN'), { plugins, theme })
t.snapshot(actual1)
const actual2 = _format(new Error('error'), { plugins, theme })
t.snapshot(actual2)
})
59 changes: 59 additions & 0 deletions test/pluginRegistry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const test = require('ava')
const proxyquire = require('proxyquire')

const pluginRegistry = proxyquire('../lib/pluginRegistry', { '../package.json': { version: '1.0.0' } })

test('registration should fail when plugin name invalid', t => {
t.throws(() => pluginRegistry.add({ name: { for: 'complex' } }), { name: 'PluginTypeError' })
})

test('registration should fail when api version unsupported', t => {
t.throws(() => pluginRegistry.add({ name: 'complex', apiVersion: 2 }), { name: 'UnsupportedApiError' })
})

test('registration should fail when installed concordance version below minimal version required by plugin', t => {
t.throws(() => pluginRegistry.add({ name: 'complex', apiVersion: 1, minimalConcordanceVersion: '2.0.0' }),
{ name: 'UnsupportedError' })
})

test('registration should fail when descriptor id used twice', t => {
const plugin = {
name: 'complex',
apiVersion: 1,
register: concordance => {
concordance.addDescriptor(1, 'complexCustomValue')
concordance.addDescriptor(1, 'complexCustomValue')
},
}
t.throws(() => pluginRegistry.add(plugin), { name: 'DuplicateDescriptorIdError' })
})

test('registration should fail when descriptor tag used twice', t => {
const plugin = {
name: 'complex',
apiVersion: 1,
register: concordance => {
concordance.addDescriptor(1, 'complexCustomValue')
concordance.addDescriptor(2, 'complexCustomValue')
},
}
t.throws(() => pluginRegistry.add(plugin), { name: 'DuplicateDescriptorTagError' })
})

test('registration should be successful', t => {
t.plan(2)
const tryDescribeValue = () => { } // eslint-disable-line unicorn/consistent-function-scoping
const plugin = {
name: 'complex',
apiVersion: 1,
serializerVersion: 1,
register: concordance => {
t.pass()
concordance.addDescriptor(1, 'complexCustomObject', 'objectDeserializer')
concordance.addDescriptor(2, 'complexCustomArray', 'arrayDeserializer')
return tryDescribeValue
},
}

t.snapshot(pluginRegistry.add(plugin))
})
51 changes: 47 additions & 4 deletions test/serialize-and-encode.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,35 @@ const test = require('ava')

const { compareDescriptors, describe, diffDescriptors, formatDescriptor } = require('..')
const { deserialize, serialize } = require('../lib/serialize')
const customErrorPlugin = require('./fixtures/customErrorPlugin')

test('serializes a descriptor into a buffer', t => {
const result = serialize(describe({ foo: 'bar' }))
t.true(Buffer.isBuffer(result))
})

const useDeserialized = (t, value) => {
const original = describe(value)
const plugins = [
{
name: 'CustomError',
apiVersion: 1,
serializerVersion: 1,
register: props => {
const custom = customErrorPlugin.factory(props)
props.addDescriptor(1, custom.tag, custom.deserialize)
return function (value) {
if (value.name === 'CustomError') {
return custom.describe
}
}
},
},
]

const useDeserialized = (t, value, options) => {
const original = describe(value, options)

const buffer = serialize(original)
const deserialized = deserialize(buffer)
const deserialized = deserialize(buffer, options)
t.true(
compareDescriptors(deserialized, original),
'the deserialized descriptor equals the original')
Expand All @@ -21,7 +39,7 @@ const useDeserialized = (t, value) => {
formatDescriptor(original),
'the deserialized descriptor is formatted like the original')

const redeserialized = deserialize(serialize(deserialized))
const redeserialized = deserialize(serialize(deserialized), options)
t.true(
compareDescriptors(redeserialized, original),
'after serializing and deserializing it again, the deserialized descriptor equals the original')
Expand Down Expand Up @@ -165,3 +183,28 @@ test('generator function', useDeserialized, function * foo () {})
test('global', useDeserialized, global)
test('promise', useDeserialized, Promise.resolve())
test('regexp', useDeserialized, /foo/gi)

test('plugin', useDeserialized, new customErrorPlugin.CustomError('custom error', 'PLUGIN', 1), { plugins })
test('should fail when plugin for deserialization missing', t => {
const deserializationPlugins = [
{
name: 'CustomError_v2',
apiVersion: 1,
serializerVersion: 2,
register: props => {
const custom = customErrorPlugin.factory(props)
props.addDescriptor(1, Symbol('CustomError_v2'), custom.deserialize)
return function (value) {
if (value.name === 'CustomError') {
return custom.describe
}
}
},
},
]

t.throws(() => {
const serialized = serialize(describe(new customErrorPlugin.CustomError('custom error', 'PLUGIN', 1), { plugins }))
deserialize(serialized, { plugins: deserializationPlugins })
}, { name: 'MissingPluginError' })
})
14 changes: 14 additions & 0 deletions test/snapshots/format.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ Generated by [AVA](https://avajs.dev).
`<\\`␊␊
>`

## format with given plugin

> Snapshot 1
`CustomError @Error {␊
code: 'PLUGIN',␊
}`

> Snapshot 2
`Error {␊
message: 'error',␊
}`

## formats ArrayBuffer

> Snapshot 1
Expand Down
Binary file modified test/snapshots/format.js.snap
Binary file not shown.
24 changes: 24 additions & 0 deletions test/snapshots/pluginRegistry.js.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Snapshot report for `test/pluginRegistry.js`

The actual snapshot is saved in `pluginRegistry.js.snap`.

Generated by [AVA](https://avajs.dev).

## registration should be successful

> Snapshot 1
{
id2deserialize: Map {
1 => 'objectDeserializer',
2 => 'arrayDeserializer',
},
name: 'complex',
serializerVersion: 1,
tag2id: Map {
'complexCustomObject' => 1,
'complexCustomArray' => 2,
},
theme: {},
tryDescribeValue: Function tryDescribeValue {},
}
Binary file added test/snapshots/pluginRegistry.js.snap
Binary file not shown.

0 comments on commit 1638c09

Please sign in to comment.