From b4c8d339be91e0747d125d3c41ec4bc2aa010691 Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Sun, 9 Jan 2022 19:59:56 +1300 Subject: [PATCH] test(type-utils): add basic tests for isTypeReadonly --- .../type-utils/tests/isTypeReadonly.test.ts | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 packages/type-utils/tests/isTypeReadonly.test.ts diff --git a/packages/type-utils/tests/isTypeReadonly.test.ts b/packages/type-utils/tests/isTypeReadonly.test.ts new file mode 100644 index 000000000000..577dbe783887 --- /dev/null +++ b/packages/type-utils/tests/isTypeReadonly.test.ts @@ -0,0 +1,138 @@ +import * as ts from 'typescript'; +import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { parseForESLint } from '@typescript-eslint/parser'; +import { + isTypeReadonly, + type ReadonlynessOptions, +} from '../src/isTypeReadonly'; +import path from 'path'; + +describe('isTypeReadonly', () => { + const rootDir = path.join(__dirname, 'fixtures'); + + describe('TSTypeAliasDeclaration ', () => { + function getType(code: string): { + type: ts.Type; + checker: ts.TypeChecker; + } { + const { ast, services } = parseForESLint(code, { + project: './tsconfig.json', + filePath: path.join(rootDir, 'file.ts'), + tsconfigRootDir: rootDir, + }); + const checker = services.program.getTypeChecker(); + const esTreeNodeToTSNodeMap = services.esTreeNodeToTSNodeMap; + + const declaration = ast.body[0] as TSESTree.TSTypeAliasDeclaration; + return { + type: checker.getTypeAtLocation( + esTreeNodeToTSNodeMap.get(declaration.id), + ), + checker, + }; + } + + function runTestForAliasDeclaration( + code: string, + options: ReadonlynessOptions | undefined, + expected: boolean, + ): void { + const { type, checker } = getType(code); + + const result = isTypeReadonly(checker, type, options); + expect(result).toBe(expected); + } + + describe('default options', () => { + const options = undefined; + + function runTestIsReadonly(code: string): void { + runTestForAliasDeclaration(code, options, true); + } + + function runTestIsNotReadonly(code: string): void { + runTestForAliasDeclaration(code, options, false); + } + + describe('basics', () => { + describe('is readonly', () => { + const runTests = runTestIsReadonly; + + // Record. + it.each([ + ['type Test = { readonly bar: string; };'], + ['type Test = Readonly<{ bar: string; }>;'], + ])('handles fully readonly records', runTests); + + // Array. + it.each([ + ['type Test = Readonly;'], + ['type Test = Readonly>;'], + ])('handles fully readonly arrays', runTests); + + // Array - special case. + // Note: Methods are mutable but arrays are treated special; hence no failure. + it.each([ + ['type Test = readonly string[];'], + ['type Test = ReadonlyArray;'], + ])('treats readonly arrays as fully readonly', runTests); + + // Set and Map. + it.each([ + ['type Test = Readonly>;'], + ['type Test = Readonly>;'], + ])('handles fully readonly sets and maps', runTests); + }); + + describe('is not readonly', () => { + const runTests = runTestIsNotReadonly; + + // Record. + it.each([ + ['type Test = { foo: string; };'], + ['type Test = { foo: string; readonly bar: number; };'], + ])('handles non fully readonly records', runTests); + + // Array. + it.each([['type Test = string[]'], ['type Test = Array']])( + 'handles non fully readonly arrays', + runTests, + ); + + // Set and Map. + // Note: Methods are mutable for ReadonlySet and ReadonlyMet; hence failure. + it.each([ + ['type Test = Set;'], + ['type Test = Map;'], + ['type Test = ReadonlySet;'], + ['type Test = ReadonlyMap;'], + ])('handles non fully readonly sets and maps', runTests); + }); + }); + }); + + describe('treatMethodsAsReadonly', () => { + const options: ReadonlynessOptions = { + treatMethodsAsReadonly: true, + }; + + function runTestIsReadonly(code: string): void { + runTestForAliasDeclaration(code, options, true); + } + + function runTestIsNotReadonly(code: string): void { + runTestForAliasDeclaration(code, options, false); + } + + describe('is readonly', () => { + const runTests = runTestIsReadonly; + + // Set and Map. + it.each([ + ['type Test = ReadonlySet;'], + ['type Test = ReadonlyMap;'], + ])('handles non fully readonly sets and maps', runTests); + }); + }); + }); +});