212 lines
6.7 KiB
TypeScript
212 lines
6.7 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
isReactComponentName,
|
|
getJSXElementBaseName,
|
|
isStringLiteralAttribute,
|
|
extractStringAttributeValue,
|
|
createSourcePositionString,
|
|
parseSourcePositionString,
|
|
} from '../../packages/plugin/src/utils/babelHelpers';
|
|
import * as t from '@babel/types';
|
|
|
|
describe('babelHelpers', () => {
|
|
describe('isReactComponentName', () => {
|
|
it('应该识别大写开头的组件名', () => {
|
|
expect(isReactComponentName('App')).toBe(true);
|
|
expect(isReactComponentName('Button')).toBe(true);
|
|
expect(isReactComponentName('MyComponent')).toBe(true);
|
|
});
|
|
|
|
it('应该识别小写开头的非组件名', () => {
|
|
expect(isReactComponentName('app')).toBe(false);
|
|
expect(isReactComponentName('button')).toBe(false);
|
|
expect(isReactComponentName('myComponent')).toBe(false);
|
|
});
|
|
|
|
it('应该处理特殊字符', () => {
|
|
expect(isReactComponentName('_App')).toBe(false);
|
|
expect(isReactComponentName('$Component')).toBe(false);
|
|
expect(isReactComponentName('123Component')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('getJSXElementBaseName', () => {
|
|
it('应该从JSXIdentifier获取名称', () => {
|
|
const identifier = t.jSXIdentifier('div');
|
|
const name = getJSXElementBaseName(identifier);
|
|
expect(name).toBe('div');
|
|
});
|
|
|
|
it('应该从JSXMemberExpression获取属性名', () => {
|
|
const memberExpr = t.jSXMemberExpression(
|
|
t.jSXIdentifier('React'),
|
|
t.jSXIdentifier('Component')
|
|
);
|
|
const name = getJSXElementBaseName(memberExpr);
|
|
expect(name).toBe('Component');
|
|
});
|
|
|
|
it('应该处理未知类型', () => {
|
|
const unknown = t.stringLiteral('test');
|
|
const name = getJSXElementBaseName(unknown as any);
|
|
expect(name).toBe('unknown');
|
|
});
|
|
});
|
|
|
|
describe('isStringLiteralAttribute', () => {
|
|
it('应该识别字符串字面量属性', () => {
|
|
const attr = t.jSXAttribute(
|
|
t.jSXIdentifier('className'),
|
|
t.stringLiteral('test')
|
|
);
|
|
|
|
const result = isStringLiteralAttribute(attr, 'className');
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('应该识别非字符串字面量属性', () => {
|
|
const attr = t.jSXAttribute(
|
|
t.jSXIdentifier('className'),
|
|
t.jSXExpressionContainer(t.identifier('classNameVar'))
|
|
);
|
|
|
|
const result = isStringLiteralAttribute(attr, 'className');
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it('应该识别属性名不匹配的情况', () => {
|
|
const attr = t.jSXAttribute(
|
|
t.jSXIdentifier('id'),
|
|
t.stringLiteral('test')
|
|
);
|
|
|
|
const result = isStringLiteralAttribute(attr, 'className');
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('extractStringAttributeValue', () => {
|
|
it('应该提取字符串属性值', () => {
|
|
const openingElement = t.jSXOpeningElement(
|
|
t.jSXIdentifier('div'),
|
|
[
|
|
t.jSXAttribute(
|
|
t.jSXIdentifier('className'),
|
|
t.stringLiteral('container')
|
|
),
|
|
]
|
|
);
|
|
|
|
const value = extractStringAttributeValue(openingElement, 'className');
|
|
expect(value).toBe('container');
|
|
});
|
|
|
|
it('应该返回null当属性不存在时', () => {
|
|
const openingElement = t.jSXOpeningElement(
|
|
t.jSXIdentifier('div'),
|
|
[]
|
|
);
|
|
|
|
const value = extractStringAttributeValue(openingElement, 'className');
|
|
expect(value).toBeNull();
|
|
});
|
|
|
|
it('应该返回null当属性不是字符串字面量时', () => {
|
|
const openingElement = t.jSXOpeningElement(
|
|
t.jSXIdentifier('div'),
|
|
[
|
|
t.jSXAttribute(
|
|
t.jSXIdentifier('className'),
|
|
t.jSXExpressionContainer(t.identifier('classNameVar'))
|
|
),
|
|
]
|
|
);
|
|
|
|
const value = extractStringAttributeValue(openingElement, 'className');
|
|
expect(value).toBeNull();
|
|
});
|
|
|
|
it('应该提取id属性值', () => {
|
|
const openingElement = t.jSXOpeningElement(
|
|
t.jSXIdentifier('div'),
|
|
[
|
|
t.jSXAttribute(
|
|
t.jSXIdentifier('id'),
|
|
t.stringLiteral('app')
|
|
),
|
|
]
|
|
);
|
|
|
|
const value = extractStringAttributeValue(openingElement, 'id');
|
|
expect(value).toBe('app');
|
|
});
|
|
});
|
|
|
|
describe('createSourcePositionString', () => {
|
|
it('应该创建正确的位置字符串', () => {
|
|
const position = createSourcePositionString('src/App.tsx', 10, 5);
|
|
expect(position).toBe('src/App.tsx:10:5');
|
|
});
|
|
|
|
it('应该处理不同的文件名', () => {
|
|
const position = createSourcePositionString('components/Button.tsx', 20, 15);
|
|
expect(position).toBe('components/Button.tsx:20:15');
|
|
});
|
|
|
|
it('应该处理行号和列号为0的情况', () => {
|
|
const position = createSourcePositionString('test.tsx', 0, 0);
|
|
expect(position).toBe('test.tsx:0:0');
|
|
});
|
|
});
|
|
|
|
describe('parseSourcePositionString', () => {
|
|
it('应该解析正确的位置字符串', () => {
|
|
const result = parseSourcePositionString('src/App.tsx:10:5');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result?.fileName).toBe('src/App.tsx');
|
|
expect(result?.lineNumber).toBe(10);
|
|
expect(result?.columnNumber).toBe(5);
|
|
});
|
|
|
|
it('应该处理不同的文件名', () => {
|
|
const result = parseSourcePositionString('components/Button.tsx:20:15');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result?.fileName).toBe('components/Button.tsx');
|
|
expect(result?.lineNumber).toBe(20);
|
|
expect(result?.columnNumber).toBe(15);
|
|
});
|
|
|
|
it('应该返回null当格式不正确时', () => {
|
|
expect(parseSourcePositionString('invalid')).toBeNull();
|
|
expect(parseSourcePositionString('src/App.tsx:10')).toBeNull();
|
|
expect(parseSourcePositionString('src/App.tsx:10:5:extra')).toBeNull();
|
|
});
|
|
|
|
it('应该返回null当行号或列号不是数字时', () => {
|
|
expect(parseSourcePositionString('src/App.tsx:abc:5')).toBeNull();
|
|
expect(parseSourcePositionString('src/App.tsx:10:def')).toBeNull();
|
|
expect(parseSourcePositionString('src/App.tsx:abc:def')).toBeNull();
|
|
});
|
|
|
|
it('应该处理行号和列号为0的情况', () => {
|
|
const result = parseSourcePositionString('test.tsx:0:0');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result?.lineNumber).toBe(0);
|
|
expect(result?.columnNumber).toBe(0);
|
|
});
|
|
|
|
it('应该处理负数行号或列号', () => {
|
|
// 虽然负数在实际情况中不应该出现,但函数应该能处理
|
|
const result = parseSourcePositionString('test.tsx:-1:-1');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result?.lineNumber).toBe(-1);
|
|
expect(result?.columnNumber).toBe(-1);
|
|
});
|
|
});
|
|
});
|
|
|