@speckle/shared
Version:
Shared code between various Speckle JS packages
210 lines (187 loc) • 5.32 kB
text/typescript
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-empty-object-type */
import { expect } from 'vitest'
import { AllAuthErrors, isAuthPolicyError } from '../authz/index.js'
import { isInstance as isResult } from 'true-myth/result'
import { isInstance as isMaybe } from 'true-myth/maybe'
import { isString } from '#lodash'
// Augment vitest types w/ new matchers
interface CustomMatchers<R = unknown> {
toBeAuthOKResult: () => R
toBeAuthErrorResult: (params: {
/**
* Check for specific error code
*/
code?: AllAuthErrors['code']
/**
* Check for specific error message
*/
message?: string | RegExp
/**
* Check for a specific payload
*/
payload?: unknown
}) => R
toBeNothingResult: () => R
toBeOKResult: (params?: {
/**
* Optionally check for specific value
*/
value?: unknown
}) => R
}
declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
interface AsymmetricMatchersContaining extends CustomMatchers {}
}
// Extend w/ extra matchers
expect.extend({
toBeOKResult(
received: unknown,
expected: Parameters<CustomMatchers['toBeOKResult']>[0]
) {
if (isMaybe(received) && received.isJust) {
received = received.value
}
if (!isResult(received)) {
return {
pass: false,
message: () => `Expected ${received} to be a Result structure`
}
}
if (!received.isOk) {
return {
pass: false,
message: () => `Expected ${received} to be an OK Result`
}
}
if (expected?.value) {
const equals = this.equals(received.value, expected.value)
if (!equals) {
return {
pass: false,
message: () =>
`Expected ${received} to be an OK Result with value ${expected.value}`,
expected: expected.value,
actual: received.value
}
}
}
return {
pass: true,
message: () => `${received} is an OK Result`
}
},
toBeAuthOKResult(received: unknown) {
if (isMaybe(received) && received.isJust) {
received = received.value
}
if (!isResult(received)) {
return {
pass: false,
message: () => `Expected ${received} to be a Result structure`
}
}
if (!received.isOk) {
return {
pass: false,
message: () => `Expected ${received} to be an OK Result`
}
}
return {
pass: true,
message: () => `${received} is an OK Result`
}
},
toBeAuthErrorResult(
received: unknown,
expected: Parameters<CustomMatchers['toBeAuthErrorResult']>[0]
) {
const { code, message, payload } = expected
if (!code?.length && !message && !payload) {
throw new Error(
'No expected value provided. Either code or message or payload must be set.'
)
}
if (isMaybe(received) && received.isJust) {
received = received.value
}
if (!isResult(received)) {
return {
pass: false,
message: () => `Expected ${received} to be a Result structure`
}
}
if (!received.isErr) {
return {
pass: false,
message: () => `Expected ${received} to be an Error Result`
}
}
if (!isAuthPolicyError(received.error)) {
return {
pass: false,
message: () => `Expected ${received} to be an Error Result with an AuthError`
}
}
// Sanity checks done, now do actual expectation checks
if (expected.code && received.error.code !== expected.code) {
return {
pass: false,
message: () =>
`Expected ${received} to be an Auth Error Result with code ${expected.code}`,
expected: expected.code,
actual: received.error.code
}
}
if (expected.message) {
const messageDoesntFit = isString(expected.message)
? !expected.message.includes(expected.message)
: !expected.message.test(received.error.message)
if (messageDoesntFit) {
return {
pass: false,
message: () =>
`Expected ${received} to be an Auth Error Result with message substring '${expected.message}'`,
expected: expected.message,
actual: received.error.message
}
}
}
if (expected.payload) {
const errPayload = received.error.payload
const equals = this.equals(errPayload, expected.payload)
if (!equals) {
return {
pass: false,
message: () =>
`Expected ${received} to be an Auth Error Result with payload ${expected.payload}`,
expected: expected.payload,
actual: errPayload
}
}
}
return {
pass: true,
message: () => `${received} is an Auth Error Result with code ${expected.code}`
}
},
toBeNothingResult(received: unknown) {
if (!isMaybe(received)) {
return {
pass: false,
message: () => `Expected ${received} to be a Maybe structure`
}
}
if (received.isJust) {
return {
pass: false,
message: () => `Expected ${received} to be a Nothing Result`
}
}
return {
pass: true,
message: () => `${received} is a Nothing Result`
}
}
})