diff --git a/.changeset/config.json b/.changeset/config.json index b1050a4..286a217 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -4,7 +4,7 @@ "commit": false, "linked": [], "access": "restricted", - "baseBranch": "master", + "baseBranch": "main", "updateInternalDependencies": "patch", "ignore": [] -} \ No newline at end of file +} diff --git a/.changeset/tiny-sloths-flash.md b/.changeset/tiny-sloths-flash.md new file mode 100644 index 0000000..d19e6a8 --- /dev/null +++ b/.changeset/tiny-sloths-flash.md @@ -0,0 +1,5 @@ +--- +'ts-japi': patch +--- + +Fixes the test framework diff --git a/package.json b/package.json index f6ed55e..abdb88d 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "A highly-modular (typescript-friendly)-framework agnostic library for serializing data to the JSON:API specification", "main": "lib/index.js", "scripts": { - "test": " jest --runInBand --verbose --coverage", + "test": "jest --runInBand --verbose --coverage", "playground": "ts-node ./benchmarks/playground.benchmark", "lint": "eslint .", "examples": "ts-node ./examples/", diff --git a/src/models/error.model.ts b/src/models/error.model.ts index 9ec4000..42ee66c 100644 --- a/src/models/error.model.ts +++ b/src/models/error.model.ts @@ -1,30 +1,37 @@ import { Dictionary, nullish } from '..'; import { ErrorOptions } from '../interfaces/error.interface'; +import { isObject } from '../utils/is-object'; import Link from './link.model'; import Meta from './meta.model'; -import { isObject } from '../utils/is-object'; export default class JapiError { /** * Tests whether `error` has similar attributes to a JapiError * - * @param error - An unknown object + * @param error An unknown object */ public static isLikeJapiError(error: unknown): error is Partial { + console.log(!isObject(error)); if (!isObject(error)) return false; - return ( - ['id', 'status', 'code', 'title', 'detail', 'source', 'links', 'meta'].some( - (attrName) => attrName in error - ) && - [ - (['id', 'status', 'code', 'title', 'detail'] as const).every( - (attrName) => !(attrName in error) || typeof error[attrName] === 'string' - ), - (['source', 'links', 'meta'] as const).every( - (attrName) => !(attrName in error) || isObject(error[attrName]) - ), - ].every((v) => v) + const hasErrorKeys = [ + 'id', + 'status', + 'code', + 'title', + 'detail', + 'source', + 'links', + 'meta', + ].some((attrName) => attrName in error); + const expectedStringKeys = (['id', 'status', 'code', 'title', 'detail'] as const).every( + (attrName) => + !(attrName in error) || error[attrName] === undefined || typeof error[attrName] === 'string' + ); + const expectedObjectKeys = (['source', 'links', 'meta'] as const).every( + (attrName) => + !(attrName in error) || error[attrName] === undefined || isObject(error[attrName]) ); + return hasErrorKeys && [expectedStringKeys, expectedObjectKeys].every((v) => v); } /** @internal */ diff --git a/test/utils/model-factory.ts b/test/utils/model-factory.ts index 1289fee..ca3158f 100644 --- a/test/utils/model-factory.ts +++ b/test/utils/model-factory.ts @@ -1,70 +1,74 @@ -import { findAllExisting } from "./find-all-existing"; -import { capitalize, camelCase } from "lodash"; -import { pushIfNotExists } from "./push-if-not-exists"; -import Base from "../models/base.model"; +import { camelCase, capitalize } from 'lodash'; +import Base from '../models/base.model'; +import { findAllExisting } from './find-all-existing'; +import { pushIfNotExists } from './push-if-not-exists'; const ModelFactory = { - addArrayAttribute( - name: string, - target: T, - source: U - ) { - const getterName = `get${capitalize(camelCase(name))}`; - target.afterRemoveHook = target.afterRemoveHook ?? []; - target.beforeSaveHook = target.beforeSaveHook ?? []; - target.prototype = target.prototype ?? ({} as any); - (target.prototype as any)[getterName] = function (this: Target) { - return findAllExisting((this as any)[name], (id: string) => source.find(id)); - }; - target.afterRemoveHook.push((model: Target) => { - (model as any)[getterName]().map((m: Source) => source.remove(m)); - }); - target.beforeSaveHook.push((model: Target) => { - findAllExisting((model as any)[name], (id: string) => source.find(id)); - }); - }, - addSingleAttribute( - name: string, - othername: string, - target: T, - source: U - ) { - const getterName = `get${capitalize(camelCase(name))}`; - target.beforeSaveHook = target.beforeSaveHook ?? []; - target.prototype = target.prototype ?? ({} as any); - (target.prototype as any)[getterName] = function (this: Target) { - return source.find((this as any)[name]); - }; - target.beforeSaveHook.push((model: Target) => { - const sourceModel = (model as any)[getterName](); - if (!sourceModel) throw new Error(`no ${name}`); - pushIfNotExists(sourceModel[othername], model.id, (id) => id === model.id); - }); - }, - createModel(model: T) { - model.storage = []; - model.find = function (this: T, id: string) { - if (this.beforeFindHook) this.beforeFindHook.forEach((hook) => hook(id)); - const result = this.storage.find((u) => u.id === id); - if (this.afterFindHook) this.afterFindHook.forEach((hook) => hook(id)); - return result; - }; - model.remove = function (this: T, obj: U) { - if (this.beforeRemoveHook) this.beforeRemoveHook.forEach((hook) => hook(obj)); - let idx = this.storage.findIndex((u) => u.id === obj.id); - if (typeof idx === "number") { - delete this.storage[idx]; - } - if (this.afterRemoveHook) this.afterRemoveHook.forEach((hook) => hook(obj)); - return obj; - }; - model.save = function (this: T, model: U) { - if (this.beforeSaveHook) this.beforeSaveHook.forEach((hook) => hook(model)); - pushIfNotExists(this.storage, model, (m) => m.id === model.id); - if (this.afterSaveHook) this.afterSaveHook.forEach((hook) => hook(model)); - return model; - }; - }, + addArrayAttribute( + name: string, + target: T, + source: U + ) { + const getterName = `get${capitalize(camelCase(name))}`; + target.afterRemoveHook = target.afterRemoveHook ?? []; + target.beforeSaveHook = target.beforeSaveHook ?? []; + if (!target.prototype) { + target.prototype = {} as any; + } + (target.prototype as any)[getterName] = function (this: Target) { + return findAllExisting((this as any)[name], (id: string) => source.find(id)); + }; + target.afterRemoveHook.push((model: Target) => { + (model as any)[getterName]().map((m: Source) => source.remove(m)); + }); + target.beforeSaveHook.push((model: Target) => { + findAllExisting((model as any)[name], (id: string) => source.find(id)); + }); + }, + addSingleAttribute( + name: string, + othername: string, + target: T, + source: U + ) { + const getterName = `get${capitalize(camelCase(name))}`; + target.beforeSaveHook = target.beforeSaveHook ?? []; + if (!target.prototype) { + target.prototype = {} as any; + } + (target.prototype as any)[getterName] = function (this: Target) { + return source.find((this as any)[name]); + }; + target.beforeSaveHook.push((model: Target) => { + const sourceModel = (model as any)[getterName](); + if (!sourceModel) throw new Error(`no ${name}`); + pushIfNotExists(sourceModel[othername], model.id, (id) => id === model.id); + }); + }, + createModel(model: T) { + model.storage = []; + model.find = function (this: T, id: string) { + if (this.beforeFindHook) this.beforeFindHook.forEach((hook) => hook(id)); + const result = this.storage.find((u) => u.id === id); + if (this.afterFindHook) this.afterFindHook.forEach((hook) => hook(id)); + return result; + }; + model.remove = function (this: T, obj: U) { + if (this.beforeRemoveHook) this.beforeRemoveHook.forEach((hook) => hook(obj)); + let idx = this.storage.findIndex((u) => u.id === obj.id); + if (typeof idx === 'number') { + delete this.storage[idx]; + } + if (this.afterRemoveHook) this.afterRemoveHook.forEach((hook) => hook(obj)); + return obj; + }; + model.save = function (this: T, model: U) { + if (this.beforeSaveHook) this.beforeSaveHook.forEach((hook) => hook(model)); + pushIfNotExists(this.storage, model, (m) => m.id === model.id); + if (this.afterSaveHook) this.afterSaveHook.forEach((hook) => hook(model)); + return model; + }; + }, }; export default ModelFactory;