Skip to content

Commit

Permalink
test: one step closer to serializer release
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanhaticus committed Nov 10, 2024
1 parent 5c19581 commit 65452ce
Show file tree
Hide file tree
Showing 24 changed files with 326 additions and 43 deletions.
4 changes: 2 additions & 2 deletions __tests__/decorators/attribute.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Chance } from 'chance';
import { Attribute, attributesSymbol } from '../../src/decorators';
import { isValidFieldKey } from '../../src/utils/isValidFieldKey';
jest.mock('../../src/utils/isValidFieldKey');
import { isValidFieldKey } from '../../src/decorators/utils/isValidFieldKey';
jest.mock('../../src/decorators/utils/isValidFieldKey');

const isValidFieldKeyMocked = jest.mocked(isValidFieldKey);

Expand Down
8 changes: 4 additions & 4 deletions __tests__/decorators/id.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Chance from 'chance';
import { Chance } from 'chance';
import { Id, idSymbol } from '../../src/decorators';
import { isValidFieldKey } from '../../src/utils/isValidFieldKey';
import { isValidFieldKey } from '../../src/decorators/utils/isValidFieldKey';

jest.mock('../../src/utils/isValidFieldKey');
jest.mock('../../src/decorators/utils/isValidFieldKey');
const isValidFieldKeyMocked = jest.mocked(isValidFieldKey);

describe('`Id`', () => {
Expand Down Expand Up @@ -54,7 +54,7 @@ describe('`Id`', () => {
metadata,
} as ClassFieldDecoratorContext);
} catch (error) {
expect(error.message).toBe(
expect((error as Error).message).toBe(
`Id() can only be applied once per class. Unable to denote ${key} as an id because ${metadata[idSymbol]} is already an id.`,
);
}
Expand Down
6 changes: 3 additions & 3 deletions __tests__/decorators/links.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Chance from 'chance';
import { Chance } from 'chance';
import { Link, linksSymbol } from '../../src/decorators';
import { isValidFieldKey } from '../../src/decorators/utils/isValidFieldKey';
import type { JSONAPILinksObject } from '../../src/types';
import { isValidFieldKey } from '../../src/utils/isValidFieldKey';

jest.mock('../../src/utils/isValidFieldKey');
jest.mock('../../src/decorators/utils/isValidFieldKey');
const isValidFieldKeyMocked = jest.mocked(isValidFieldKey);

describe('`Link`', () => {
Expand Down
4 changes: 2 additions & 2 deletions __tests__/decorators/meta.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Chance } from 'chance';
import { Meta, metaSymbol } from '../../src/decorators';
import { isValidFieldKey } from '../../src/decorators/utils/isValidFieldKey';
import type { JSONDataTypes } from '../../src/types';
import { isValidFieldKey } from '../../src/utils/isValidFieldKey';

jest.mock('../../src/utils/isValidFieldKey');
jest.mock('../../src/decorators/utils/isValidFieldKey');

const isValidFieldKeyMocked = jest.mocked(isValidFieldKey);

Expand Down
4 changes: 2 additions & 2 deletions __tests__/decorators/relationship.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Chance } from 'chance';
import { Relationship, relationshipsSymbol } from '../../src/decorators';
import { isValidFieldKey } from '../../src/utils/isValidFieldKey';
import { isValidFieldKey } from '../../src/decorators/utils/isValidFieldKey';

jest.mock('../../src/utils/isValidFieldKey');
jest.mock('../../src/decorators/utils/isValidFieldKey');

const isValidFieldKeyMocked = jest.mocked(isValidFieldKey);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Chance } from 'chance';
import { buildSymbol } from '../../src/utils/buildSymbol';
import { buildSymbol } from '../../../src/decorators/utils/buildSymbol';

describe('`buildSymbol`', () => {
let chance: Chance.Chance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {
firstOnlyCharacters,
middleOnlyCharacters,
reservedCharacters,
} from '../../src/constants/characterSets';
import { isValidFieldKey } from '../../src/utils/isValidFieldKey';
} from '../../../src/decorators/constants/characterSets';
import { isValidFieldKey } from '../../../src/decorators/utils/isValidFieldKey';

describe('`isValidFieldKey`', () => {
let chance: Chance.Chance;
Expand All @@ -20,7 +20,7 @@ describe('`isValidFieldKey`', () => {
try {
isValidFieldKey(decoratorName, key);
} catch (error) {
expect(error.message).toContain(
expect((error as Error).message).toContain(
`@${decoratorName} can only be applied to specific keys. Expected key ${key.toString()}`,
);
}
Expand All @@ -32,7 +32,7 @@ describe('`isValidFieldKey`', () => {
try {
isValidFieldKey('some-decorator', key);
} catch (error) {
expect(error.message).toContain(
expect((error as Error).message).toContain(
`Expected key ${key.toString()} to be of type string, but received ${typeof key}.`,
);
}
Expand All @@ -44,7 +44,9 @@ describe('`isValidFieldKey`', () => {
try {
isValidFieldKey('some-decorator', key);
} catch (error) {
expect(error.message).toContain('Expected key to be non-empty.');
expect((error as Error).message).toContain(
'Expected key to be non-empty.',
);
}
});

Expand All @@ -54,7 +56,7 @@ describe('`isValidFieldKey`', () => {
try {
isValidFieldKey('some-decorator', key);
} catch (error) {
expect(error.message).toContain(
expect((error as Error).message).toContain(
`Expected key ${key} to not contain any reserved characters, but found ${key}.`,
);
}
Expand All @@ -67,7 +69,7 @@ describe('`isValidFieldKey`', () => {
try {
isValidFieldKey('some-decorator', key);
} catch (error) {
expect(error.message).toContain(
expect((error as Error).message).toContain(
`Expected key ${key} to not contain the characters ${firstOnlyCharacter}, except as the first character.`,
);
}
Expand All @@ -87,7 +89,7 @@ describe('`isValidFieldKey`', () => {
try {
isValidFieldKey('some-decorator', key);
} catch (error) {
expect(error.message).toContain(
expect((error as Error).message).toContain(
`Expected key ${key} to not contain the characters ${middleOnlyCharacter}, ${middleOnlyCharacter} as the first or last character.`,
);
}
Expand Down
88 changes: 88 additions & 0 deletions __tests__/serializers/utils/assertMetadataIsPresent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { assertMetadataIsPresent } from '../../../src/serializers/utils/assertMetadataIsPresent';

describe('`assertMetadataIsPresent`', () => {
it('should throw an error if `Symbol.metadata` is undefined', () => {
const originalSymbolMetadata = Symbol.metadata;

// @ts-expect-error
Symbol.metadata = undefined;

try {
assertMetadataIsPresent({});
} catch (error) {
expect((error as Error).message).toEqual(
'Failed to assert the presence of metadata because the metadata symbol is undefined. You may need to import the `@tsmetadata/polyfill` package.',
);
}

// @ts-expect-error
Symbol.metadata = originalSymbolMetadata;
});

describe('when the candidate is an array of objects', () => {
it('should throw an error if at least one candidate is not an object', () => {
const candidate = [1, {}];

try {
assertMetadataIsPresent(candidate);
} catch (error) {
expect((error as Error).message).toEqual(
'Failed to assert the presence of metadata because at least one candidate is not an object, meaning no constructor is present.',
);
}
});

it('should throw an error if no metadata is found on an object constructor', () => {
const candidate = [{}, {}];

try {
assertMetadataIsPresent(candidate);
} catch (error) {
expect((error as Error).message).toEqual(
'No metadata was found on an object constructor.',
);
}
});

it('should return `true` if metadata is found on all object constructors', () => {
const candidate = [
{ constructor: { [Symbol.metadata]: 'metadata' } },
{ constructor: { [Symbol.metadata]: 'metadata' } },
];

expect(assertMetadataIsPresent(candidate)).toBe(true);
});
});

describe('when the candidate is an object', () => {
it('should throw an error if the candidate is not an object', () => {
const candidate = 1;

try {
assertMetadataIsPresent(candidate);
} catch (error) {
expect((error as Error).message).toEqual(
'Failed to assert the presence of metadata because at least one candidate is not an object, meaning no constructor is present.',
);
}
});

it('should throw an error if no metadata is found on the object constructor', () => {
const candidate = {};

try {
assertMetadataIsPresent(candidate);
} catch (error) {
expect((error as Error).message).toEqual(
'No metadata was found on an object constructor.',
);
}
});

it('should return `true` if metadata is found on the object constructor', () => {
const candidate = { constructor: { [Symbol.metadata]: 'metadata' } };

expect(assertMetadataIsPresent(candidate)).toBe(true);
});
});
});
43 changes: 43 additions & 0 deletions __tests__/serializers/utils/getMetadataBySymbol.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Chance } from 'chance';
import { assertMetadataIsPresent } from '../../../src/serializers/utils/assertMetadataIsPresent';
import { getMetadataBySymbol } from '../../../src/serializers/utils/getMetadataBySymbol';

jest.mock('../../../src/serializers/utils/assertMetadataIsPresent');
const assertMetadataIsPresentMocked = jest.mocked(assertMetadataIsPresent);

describe('`getMetadataSymbol`', () => {
let chance: Chance.Chance;

beforeEach(() => {
chance = new Chance();
});

it('should assert metadata is present in the given object', () => {
const object = {
constructor: {
[Symbol.metadata]: {},
},
};

getMetadataBySymbol(object, Symbol('test'));

expect(assertMetadataIsPresentMocked).toHaveBeenCalledTimes(1);
expect(assertMetadataIsPresentMocked).toHaveBeenCalledWith(object);
});

it("should return the symbol's metadata on the given object", () => {
const symbol = Symbol(chance.string());

const object = {
constructor: {
[Symbol.metadata]: {
[symbol]: chance.string(),
},
},
};

const metadata = getMetadataBySymbol(object, symbol);

expect(metadata).toBe(object.constructor[Symbol.metadata][symbol]);
});
});
15 changes: 15 additions & 0 deletions __tests__/serializers/utils/isObject.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { isObject } from '../../../src/serializers/utils/isObject';

describe('`isObject`', () => {
it('should return `false` when the value is `null`', () => {
expect(isObject(null)).toBe(false);
});

it('should return `false` when the value is not an object', () => {
expect(isObject('')).toBe(false);
});

it('should return `true` when the value is an object', () => {
expect(isObject({})).toBe(true);
});
});
13 changes: 13 additions & 0 deletions __tests__/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@tsmetadata/polyfill/lib/tsconfig.polyfill.json",
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true
},
"include": ["./**/*.ts"]
}
1 change: 1 addition & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Config } from 'jest';

const config: Config = {
preset: 'ts-jest',
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
testEnvironment: 'node',
coverageThreshold: {
global: {
Expand Down
5 changes: 5 additions & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import '@tsmetadata/polyfill';

afterEach(() => {
jest.clearAllMocks();
});
Loading

0 comments on commit 65452ce

Please sign in to comment.